概述

  • python3.6新增特性
  • 新增f字符串
  • 数字中的下划线
  • 异步生成器
  • 异步推导式
  • 新增方法:`__init_subclass__`
  • 新增方法:`__set_name__`
  • 路径支持使用对象
  • 路径默认编码改为utf-8
  • Windows控制台编码改为utf-8
  • 新的dict实现
  • 新增secrets模块
  • python3.7新增特性
  • 新增dataclass
  • 新增importlib.resources
  • python3.8
  • :=
  • 函数参数新增`/`语法
  • f字符串新增=语法
  • 具有外部数据缓冲区的 pickle 协议 5
  • 新增importlib.metadata模块
  • python3.9
  • 字典之间新增`|`和`|=`运算符
  • 字符串新增两个方法


python3.6新增特性

https://docs.python.org/zh-cn/3.6/whatsnew/3.6.html

新增f字符串

用法和format基本是一样的

>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'
>>> "He said his name is {name}.".foramt(name=name)
'He said his name is Fred.'
>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}"  # nested fields
'result:      12.35'
>>> "result: {value:{width}.{precision}}".format(width=width,precision=precision, value=value)
'result:      12.35'

只是把format写法精简了,更多的格式化语法可以看: https://docs.python.org/zh-cn/3.6/library/string.html#formatspec

数字中的下划线
>>> 1_0_0_0
1000
>>> 1_000_000_000_000_000
1000000000000000
>>> 0x_FF_FF_FF_FF
4294967295

允许在数字之间添加下划线让代码更好看。不能再开头和结尾出现下划线,而且不能连续出现两个下划线

另外format语法也支持_

>>> '{:_}'.format(1000000)
'1_000_000'
>>> '{:_x}'.format(0xFFFFFFFF)
'ffff_ffff'
异步生成器

允许在异步函数内同时出现yield和await,也就是可以实现异步生成器

async def ticker(delay, to):
    """Yield numbers from 0 to *to* every *delay* seconds."""
    for i in range(to):
        yield i
        await asyncio.sleep(delay)
异步推导式

result = [i async for i in aiter() if i % 2]result = [await fun() for fun in funcs if await condition()] 这种语法我感觉用不上

新增方法:__init_subclass__

没看懂,略

新增方法:__set_name__

没看懂,略

路径支持使用对象

在之前的版本里,传入一个路径基本都是使用字符串,现在可以使用pathlib.Path("/root/1.txt")),它实现了__fspath__来表示实际的路径

>>> import pathlib
>>> with open(pathlib.Path("README")) as f:
...     contents = f.read()
...
>>> import os.path
>>> os.path.splitext(pathlib.Path("some_file.txt"))
('some_file', '.txt')
>>> os.path.join("/a/b", pathlib.Path("c"))
'/a/b/c'
>>> import os
>>> os.fspath(pathlib.Path("some_file.txt"))
'some_file.txt'

这篇文章详细的介绍了:https://zhuanlan.zhihu.com/p/87940289

路径默认编码改为utf-8

python3.5是mbcs。

>>> import sys
>>> sys.getfilesystemencoding()
'mbcs'

正常来说是没有影响的,因为操作路径一般给的都是字符串而不是字符,总不会有人这么写文件吧

with open("中国.txt".encode(), 'w') as f:
    pass

https://peps.python.org/pep-0529/

Windows控制台编码改为utf-8

sys.stdin, sys.stdout和sys.stderr默认编码都是utf-8,

当然,这是Windows的cmd里面出现乱码的原因,因为cmd默认编码是gbk

python Field定义 python _fields__开发语言

cmd修改编码很简单:chcp 65001。想改回gbkchcp 936

新的dict实现

新dict的内存使用量会比之前减少20%到25%,而且现在的字典是有序的,当然这不是刻意保留的特性,未来可能会改变

新增secrets模块

就是一些随机数或者字符串的方法,一般用不上
https://docs.python.org/zh-cn/3.6/library/secrets.html#module-secrets

python3.7新增特性

新增dataclass

顾名思义就是一个装数据的类, 会自己生成__init____repr____eq____hash__

@dataclass
class Point:
    x: float
    y: float
    z: float = 0.0

p = Point(1.5, 2.5)
print(p)   # produces "Point(x=1.5, y=2.5, z=0.0)"
新增importlib.resources

用于更好读取的import 导入的包,它不一定是文件系统内实际存在的文件或文件夹,比如在zip压缩包内等

import importlib.resources as res
import tkinter
 
text = res.read_text(tkinter, 'dialog.py', encoding='utf-8', errors='strict')
print(text)

python3.8

:=
if (n := len(a)) > 10:
    print(f"List is too long ({n} elements, expected <= 10)")

上面的语法相当于n = len(a)n>10,只是为了len这个方法不被调用两次。当然这个例子不是很直观。

while (block := f.read(256)) != '':
    process(block)

当读取到空字符串的时候就停止,如果这个改成常规写法应该是下面这样的(或者直接while True),是不是变的更简洁了

block = f.read(256)
while block != '':
    process(block)
    block = f.read(256)

还有一种情况是在列表推导式中
[f(x) for x in range(10) if f(x)>0] f(x)被运行了两次
[y for x in range(10) if (y:=f(x)) >0] 这样就只运行了一次

函数参数新增/语法

*类似,看例子

def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)

a, b参数不能使用关键词传参,只能传值。c,d既可以传值,也可以传键值,e,f只能传键值
比如:f(10, 20, 30, d=40, e=50, f=60)是允许的,而f(10, b=20, c=30, d=40, e=50, f=60)是错误的

f字符串新增=语法
user = 'eric_idle'
member_since = date(1975, 7, 31)
f'{user=} {member_since=}'
# "user='eric_idle' member_since=datetime.date(1975, 7, 31)"
具有外部数据缓冲区的 pickle 协议 5

pickle新增缓冲区来减少数据拷贝,与之前的Python版本的pickle可能存在不兼容的情况

新增importlib.metadata模块

用于读取模块的一些信息

>>> from importlib.metadata import version, requires, files
>>> version('requests')
'2.22.0'
>>> list(requires('requests'))
['chardet (<3.1.0,>=3.0.2)']
>>> list(files('requests'))[:5]
[PackagePath('requests-2.22.0.dist-info/INSTALLER'),
 PackagePath('requests-2.22.0.dist-info/LICENSE'),
 PackagePath('requests-2.22.0.dist-info/METADATA'),
 PackagePath('requests-2.22.0.dist-info/RECORD'),
 PackagePath('requests-2.22.0.dist-info/WHEEL')]

python3.9

字典之间新增||=运算符

首先给了个字典合并的几种方法

d = {'spam': 1, 'eggs': 2, 'cheese': 3}
e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}

# 方法1
print({**d, **e})
# 方法2
from collections import ChainMap
print(dict(ChainMap(e, d)))
# 方法3
print(dict(d, **e))
#方法4
d.update(e)
print(d)

然后给出了python3.9的第五种方法: print(d | e)

注意d|ee|d结果(顺序和值)可能是不一样的,这和之前的四种方法一样执行有先后的顺序

虽然|很方便,但还是无法处理所有的情况,比如print({'a': [1, 2]} | {'a': [3, 4]})是应该得到{'a': [1, 2, 3, 4]} 还是 {'a': [[1, 2], [3, 4]]},这种就只能自己写方法去实现了

字符串新增两个方法

实现如下

def removeprefix(self: str, prefix: str, /) -> str:
    if self.startswith(prefix):
        return self[len(prefix):]
    else:
        return self[:]

def removesuffix(self: str, suffix: str, /) -> str:
    # suffix='' should not call self[:-0].
    if suffix and self.endswith(suffix):
        return self[:-len(suffix)]
    else:
        return self[:]

使用例子:

if test_func_name.startswith("test_"):
    print(test_func_name[5:])
else:
    print(test_func_name)

改为: print(test_func_name.removeprefix("test_"))