Python3.10 新特性

简介

Python3.10 发布于2021年10月14日,这儿总结一下改版本引入的一些新功能

官方新特性链接 Python3.10 新特性

安装

此处主要介绍在Ubuntu下安装 Python3.10

  1. 添加deadsnakes源
    • sudo add-apt-repository ppa:deadsnakes/ppa
    • sudo apt-get update
  2. 安装 Python3.10
    • sudo apt install python3.10-full
  3. 安装 Python3.10 的pip
    • python3.10 -m ensurepip --upgrade

结构模式匹配(match case)

1
2
3
4
5
6
7
8
9
10
11
# 通用语法

match subject:
case <pattern_1>:
<action_1>
case <pattern_2>:
<action_2>
case <pattern_3>:
<action_3>
case _:
<action_wildcard>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def http_error(status):
match status:
case 400:
return "Bad request"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case 455 | 456:
return "This is a custom error"
case _:
return "Something's wrong with the Internet"

print(http_error(418))
print(http_error(455))
print(http_error(456))
print(http_error(499))

# I'm a teapot
# This is a custom error
# This is a custom error
# Something's wrong with the Internet

带有字面值和变量的模式

1
2
3
4
5
6
7
8
9
10
11
12
# point is an (x, y) tuple
match point:
case (0, 0):
print("Origin")
case (0, y):
print(f"Y={y}")
case (x, 0):
print(f"X={x}")
case (x, y):
print(f"X={x}, Y={y}")
case _:
raise ValueError("Not a point")

模式和类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Point:
x: int
y: int

def location(point):
match point:
case Point(x=0, y=0):
print("Origin is the point's location.")
case Point(x=0, y=y):
print(f"Y={y} and the point is on the y-axis.")
case Point(x=x, y=0):
print(f"X={x} and the point is on the x-axis.")
case Point():
print("The point is located somewhere else on the plane.")
case _:
print("Not a point")

约束项

1
2
3
4
5
match point:
case Point(x, y) if x == y:
print(f"The point is located on the diagonal Y=X at {x}.")
case Point(x, y):
print(f"Point is not on the diagonal.")

复杂模式和通配符

1
2
3
4
5
match test_variable:
case ('warning', code, 40):
print("A warning has been received.")
case ('error', code, _):
print(f"An error {code} occurred.")

更好的错误信息

语法错误(SynaxErrors)

字典未关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
test_dict = {1: 1, 2: 2, 3: 3

# Python3.9
"""
File "/home/stolen/test.py", line 2

^
SyntaxError: unexpected EOF while parsing
"""

# Python3.10
"""
File "/home/stolen/test.py", line 1
test_dict = {1: 1, 2: 2, 3: 3
^
SyntaxError: '{' was never closed
"""

冒号缺失

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if 1 > 2
print('abc')

# Python3.9
"""
File "/home/stolen/test.py", line 1
if 1 > 2
^
SyntaxError: invalid syntax
"""

# Python3.10
"""
File "/home/stolen/test.py", line 1
if 1 > 2
^
SyntaxError: expected ':'
"""

判断等于错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if bool(3.14) = True:
print('true')

# Python3.9
"""
File "/home/stolen/test.py", line 1
if bool(3.14) = True:
^
SyntaxError: invalid syntax
"""

# Python3.10
"""
File "/home/stolen/test.py", line 1
if bool(3.14) = True:
^^^^^^^^^^
SyntaxError: cannot assign to function call here. Maybe you meant '==' instead of '='?
"""

缩进错误(IndentationErrors)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if bool(3.14) == True:
print('true')

# Python3.9
"""
File "/home/project/demo.py", line 2
print('true')
^
IndentationError: expected an indented block
"""

# Python3.10
"""
File "/home/project/demo.py", line 2
print('true')
^
IndentationError: expected an indented block after 'if' statement on line 1
"""

属性错误(AttributeErrors)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
a = 'abc'
a.isnumerics()

# Python3.9
"""
Traceback (most recent call last):
File "/home/project/demo.py", line 2, in <module>
a.isnumerics()
AttributeError: 'str' object has no attribute 'isnumerics'
"""

# Python3.10
"""
Traceback (most recent call last):
File "/home/project/demo.py", line 2, in <module>
a.isnumerics()
AttributeError: 'str' object has no attribute 'isnumerics'. Did you mean: 'isnumeric'?
"""

命名错误(NameErrors)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
hello = 'hello, world!'
print(hallo)

# Python3.9
"""
Traceback (most recent call last):
File "/home/project/demo.py", line 2, in <module>
print(hallo)
NameError: name 'hallo' is not defined
"""

# Python3.10
"""
Traceback (most recent call last):
File "/home/project/demo.py", line 2, in <module>
print(hallo)
NameError: name 'hallo' is not defined. Did you mean: 'hello'?
"""

类型提示相关的新功能

从 Python3.5 开始正式引入 typing 模块,从 Python3.6 开始已经获得全面的类型声明的支持,一下将介绍 Python3.10 中的变化

Union 可以用 | 简写

1
2
3
4
5
6
7
8
# Python3.9
from typing import Union
def square(number: Union[int, float]) -> Union[int, float]:
return number ** 2

# Python3.10
def square(number: int | float) -> int | float:
return number ** 2

这种语法也可以用在 isinstance 中 isinstance(item, int | str)

类型别名

现在可以对类型别名变量做TypeHint

1
2
3
4
5
6
7
8
9
10
# Python3.9
MyType = str
def foo(something: MyType) -> MyType:
return something

# Python3.10
from typing import TypeAlias
MyType: TypeAlias = str
def foo(something: MyType) -> MyType:
return something

带括号的上下文管理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
with (CtxManager() as example):
...

with (
CtxManager1(),
CtxManager2()
):
...

with (CtxManager1() as example,
CtxManager2()):
...

with (CtxManager1(),
CtxManager2() as example):
...

with (
CtxManager1() as example1,
CtxManager2() as example2
):
...

zip的长度检查

默认情况下 zip 在最短的迭代次数用尽时停止,现在加入了一个 strict=False 参数,默认情况不检查长度,如果 strict=True 时,如果可迭代项长度不相等,则会引发 ValueError

1
2
3
4
5
list(zip(range(3), ['a', 'b', 'c', 'd'], strict=True))
# [(0, 'a'), (1, 'b'), (2, 'c')]

list(zip(range(3), ['a', 'b', 'c', 'd'], strict=True))
# ValueError: zip() argument 2 is longer than argument 1

字典视图映射

字典的三个方法 dict.keys()、dict.values() 和 dict.items() 会返回不同的视图,现在都增加了 mapping 属性,可以返回原始字典。

1
2
3
4
5
6
7
data={'python':2021,'java':2020}
k=data.keys()
print(k)
print(k.mapping)

# dict_keys(['python', 'java'])
# {'python': 2021, 'java': 2020}

为整数添加 popcount 计算方法

汉明重量是一串符号中非零符号的个数,是以理查德·卫斯里·汉明的名字命名的,它在包括信息论、编码理论、密码学等多个领域都有应用。

在密码学以及其它应用中经常需要计算数据位中 1 的个数,针对如何高效地实现人们已经广泛地进行了研究。

Python3.10 为整数类型增加了一个新方法 int.bit_count() 可以返回给定整数的二进制位中 1 的个数。

1
2
3
4
5
6
a = 11
print(bin(a)) #a的二进制表示
print(a.bit_count())

# 0b1011
# 3