Python 3.10刚刚发布,这意味着我们终于可以看到有哪些新特性了。所以我们来看看,好吗?
结构模式匹配
这是一个大问题--这可能是自2008年Python 3.0发布以来最大的语法补充。
结构模式匹配 "的真正含义是,现在我们有了一种方法,可以根据一段数据的结构,而不是逻辑条件来编写条件语句。它是通过一个新的match 关键字和多个case 子句完成的:
status = get_http_status()
match status:
case 200:
print('OK')
case 404:
print('Not Found')
case _:
print(f'Unknown status: {status}')
你可能会认为这看起来与其他语言中另一个流行的功能非常相似:开关语句。你是对的--它绝对可以作为switch-case的替代品,但match 做的更多。这里有几个例子。
匹配一个数据结构中的元素
command = ['move', 'right']
match command:
case ['move', direction]:
print(f'Player moved in {direction} direction.')
case ['attack', enemy]:
print(f'Player attacked {enemy}.')
case _:
print('Unknown command.')
# Output:
# Player moved in right direction.
匹配一个对象中的属性
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
vec = Vector(3, 5)
match vec:
case Vector(x, 0):
print(f'Vector lies on Y-axis with {x=}')
case Vector(0, y):
print(f'Vector lies on X-axis with {y=}')
case Vector(x, y):
print(f'Vector lies on {x=}, {y=}')
# Output:
# Vector lies on x=3, y=5
使用传播语法匹配可变数量的属性
msg = {'type': 'collect', 'orbs': 10, 'badges': 30}
match msg:
case {'type': 'collect', **bag}:
print('Collected items:')
for name, count in bag.items():
print(f'{name} - {count}')
case {'type': 'drop', **bag}:
print(f"Dropped items: {', '.join(bag)}")
case _:
print('Unknown message')
# Output:
# Collected items:
# orbs - 10
# badges - 30
更好的错误信息
尽管Python在可读性方面很友好,但它的错误信息有时却相当难以理解。幸运的是,Python 3.10 在其错误信息的可读性方面带来了巨大的改进。
其中一些改进的信息是
>>> if rocket.position = event_horizon:
File "<stdin>", line 1
if rocket.position = event_horizon:
^
SyntaxError: cannot assign to attribute here. Maybe you meant '==' instead of '='?
>>> collections.namedtoplo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'collections' has no attribute 'namedtoplo'. Did you mean: namedtuple?
>>> values = {x:1, y:2, z w:3}
File "<stdin>", line 1
values = {x:1, y:2, z w:3}
^
SyntaxError: ':' expected after dictionary key
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized
新的类型联合运算符
typing 模块的一个非常常见的用法是创建联合数据类型,即可以访问多种数据类型的变量。要做到这一点,我们需要导入typing.Union ,像这样:
def double(value: Union[int, str]) -> Union[int, str]:
return value * 2
由于这是一个非常普遍的使用情况,我们为相同的功能添加了一个速记:你现在可以使用| 操作符来创建数据类型的联盟:
def double(value: int | str) -> int | str:
return value * 2
scrict zip() 函数中的参数
Python 内置的zip 函数相当方便,它接收一堆迭代变量,并从每一个迭代变量中返回一个值,直到任何一个迭代变量的值用完。比如说:
nums = [1, 2, 3]
letters = ['a', 'b', 'c']
for letter, num in zip(letters, nums):
print(f'{letter}: {num}')
# Output:
# a: 1
# b: 2
# c: 3
zip 的问题是,如果其中一个迭代表比另一个迭代表长,那么这些结束值将永远不会出现在压缩包中,而你将无从得知:
nums = [1, 2, 3, 4, 5, 6]
letters = ['x', 'y', 'z']
for letter, num in zip(letters, nums):
print(f'{letter}: {num}')
# Output:
# x: 1
# y: 2
# z: 3
我们错过了nums 中的4、5和6,而没有办法知道这一点。为了弥补这一点,我们引入了新的strict 参数,如果任何一个迭代项的长度不同,就会抛出一个错误:
nums = [1, 2, 3, 4, 5, 6]
letters = ['x', 'y', 'z']
for letter, num in zip(letters, nums, strict=True):
print(f'{letter}: {num}')
# Output:
# x: 1
# y: 2
# z: 3
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# ValueError: zip() argument 2 is longer than argument 1
废弃了distutils 模块
distutils 包是创建可分发的 Python 包的老方法,例如上传到PyPI。该包的功能已经被第三方软件包setuptools 和packaging 所取代。正因为如此,它在3.10中被废弃,并将在3.12中被删除。
其他改进
- 增加了
int.bit_count()方法,用于返回一个数字的二进制表示中的1位数。 - 增加了其他
typing模块:TypeAlias类型,以及用户定义的类型守护与TypeGuard。 - 增加了
sys.orig_argv属性,它包含传递给python命令的原始args。
总结
今年我们得到了一些非常激动人心的大的更新!要想更详细地了解这个版本中的变化,你可以查看文档。
另外,如果你想了解明年Python中会出现什么,你可以关注Python邮件列表中的发展,以及最新的开放PEPs。明年的计划似乎已经非常有趣了。👀