Python 3.10 关键新特性

Python 3.10 于 2021-10-04 发布,至今已大半年,目前 AWS 的 Lambda 尚未直接支持,但用 Docker 镜像的方式使用 AWS Lambda 是可以使用 Python 3.10。Python 一年一发布的节奏比 Java LTS 还紧密。下一个版本 Python 3.11 预计在 2022-10-03 发布。在学习 Python 3.10 之前先回顾一下 Python 3.7, 3.8, 3.9 的特性(不想关心之前版本的变迁可直接跳跃到下方的 Python 3.10 新特性去)

Python 3.7 所带来的新特性

  1. breakpoint()
  2. 数据类(@dataclass)
  3. 类型提示强化和延迟注解求值
  4. 时间精度的提高
  5. 保证字典的顺序
  6. async 和 await 成为关键字
  7. asyncio.run() 简化事件循环
  8. 上下文变量(ContextVar) - 可实现 ThreadLocal 和 SLF4J 的 MDC 功能

体验一下 Python 3.8 带来的主要新特性

  1. 赋值表达式(:=) -- Walrus Operator
  2. 可限定只按位置传递参数
  3. 更精确的类型提示(增强了 Type Hints)
  4. 用 f-strings 进行简单的调试(f"{name = }" 输出 name = 'Eric'
  5. 新模块 importlib.metadata
  6. Math 和 Statistics 函数
  7. 更聪明的警告信息

Python 3.9 新特性回顾

  1. 字典的并集操作( d1 | d2)
  2. 删除字符串前缀和后缀的函数(removeprefix(), removesuffix())
  3. 更简单的泛型提示(list[str], 而不用 typing.List[str])
  4. DateTime 新增时区支持(不再依赖 pytz)
  5. shutdown() Executor 时可取消待处理任务
  6. random.Random.randbytes() 生成随机字节
  7. typing.Annotated 类型提示(distance: Annotated[float, 'feet'] 类型加注解提示)

回顾完上面后,开始学习 Python 3.10 的新特性, 参考 What's New In Python 3.10

带圆括号的上下文管理器

使用 Python 3.9.12 的 with 就可以一次管理个资源,如

不知道为什么把它作为了 Python 3.10 的新特性,而且经测试 Python 3.9.0 就能用圆括号框住多个资源,Python 3.8 不支持 with 圆括号的语法

更友好的错误提示

[1, , {a:2, 2: 会提示 '[' was never closed'{" was never closed, 而不是笼统的说 invalid syntax

还有更多的更聪明的错误提示,没必要一一列出,反正也不影响如何书写代码,只是看到了错误信息容易定位错误,多用,谁用谁知道

结构化模式匹配

Python 没有 switch 语句,所以不得不用 if...elif..else 语句,不过现在 Python 3.10 从 Scala 学来了更高级的 match...case 语句。模式匹配功能很强大,展开来值得单独写一篇

匹配字面值

执行后输出为

Bad request
None
--
Not found
Not allowed
Unknown

Python 的 match...case 是语句,而非表达式,所以它本身不能赋值给变量的。

每个 case 后相当于自动加上了 break 语句, case _: 相当于 case default:, case 后的多个匹配可用 | 连接。

没有 case _: 的 match 相当于什么也没匹配到,是一个 no-op 操作行为,如果以上函数中拿掉 case _:, http_error(405) 得到的就是 None

更强大的匹配功能还在后头,比如对类型,类型值的匹配,首先看它如何匹配一个元组,并获取其中的值

执行后输出为

Is a tuple
y = 3
Origin

进一步延伸,可以有更丰富的匹配功能

  1. case []:  是一个列表
  2. case [1, 3, a]: 匹配前两个值为 1, 3 的三元素列表,第三个元素赋给 a 变量
  3. case [1,2, *a]: 结合 Python 的集合拆解功能, 这里匹配至少两元素的列表,头两元素为 1, 2, 其余元素赋给 a 列表
  4. case Point(x=0, y=0): 假如声明了类 class Point: x: int; y: int, 它则可匹配到 x=0, y=0 的 Point 对象,
  5. case Point(x=xvar, y=yvar): 匹配 Point 类型,并捕获 x, y 的值,用 xvaryvar 引用 x, y 的值
  6. case Point(): 匹配 Point 类型,相当于 isinstance(p, Point)
  7. case [Point(0,0)]: 嵌套匹配 Point(0,0) 单元素列表

如果用 case Point(x,y), 则会报错

case Point(x, y):
TypeError: Point() accepts 0 positional sub-patterns (2 given)

因为在 Point 中 x, y 是没有顺序的, 相当于是按名赋值的,只要给 Point 声明一个 __match_args__ 则可用 Point(x, y) 进行匹配,完整代码如下

输出为

x = 1, y = 2

  1. case Point(x, y) if x == y: 加约束条件的匹配
  2. case {"name": b, "id": 1}: 匹配字典
  3. case {"name": b, **rest}: 匹配字典剩余的项
  4. case (Point(x1, y1, Point(x2, y2) as p2): 用 as 关键字捕获子模式
  5. 匹配枚举值

EncodingWarning 提示

增加 -X warn_default_encoding 选项和 PYTHONWARNDEFAULTENCODING 来启用相应警告,用于定位由于打开文件编码引起的问题

新的联合类型提示

Python 3.10 前的联合类型提示用 typing.Union

number: Union[int, float]

现在直接用 |

number: int | float

在进行实例类型判断时也可以用 |, 如

isinstance(1, int | str)

类型别名

Python 3.10 之前类型别名和使用是这样写

这样让 StrCache 看起就像是一个值为 Cache[str] 的字符串变量,也确实是,用 type(StrCache) 得到的就是 <class 'str'>.

Python 3.10 的写法让它看起来更像是一个类型

因为他们是 type hints 的范畴,所以本质上都是

类型别名用作内置类型提示

更严格的 zip() 函数

zip() 函数作用于两个序列,生成 tuple 序列,Python 不要求两个序列等长,只以短序列为准,长序列多出部分被忽略

这会造成两个序列都比较长的时候,得到非期望的结果,多数时候我们应用 zip() 函数想要完全配对。所以在 Python 3.10 中加入了 strict 参数

最后总结,Python 3.10 的一个关键特性就是结构化模式匹配。

链接:

  1. Python 3.10: Cool New Features for You to Try

本文链接 https://yanbin.blog/python-3-10-new-features/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments