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 所带来的新特性
体验一下 Python 3.8 带来的主要新特性
Python 3.9 新特性回顾
回顾完上面后,开始学习 Python 3.10 的新特性, 参考 What's New In Python 3.10
使用 Python 3.9.12 的
不知道为什么把它作为了 Python 3.10 的新特性,而且经测试 Python 3.9.0 就能用圆括号框住多个资源,Python 3.8 不支持 with 圆括号的语法
还有更多的更聪明的错误提示,没必要一一列出,反正也不影响如何书写代码,只是看到了错误信息容易定位错误,多用,谁用谁知道
匹配字面值
执行后输出为
每个 case 后相当于自动加上了
没有
更强大的匹配功能还在后头,比如对类型,类型值的匹配,首先看它如何匹配一个元组,并获取其中的值
执行后输出为
如果用 case Point(x,y), 则会报错
输出为
这样让
Python 3.10 的写法让它看起来更像是一个类型
因为他们是 type hints 的范畴,所以本质上都是
类型别名用作内置类型提示
这会造成两个序列都比较长的时候,得到非期望的结果,多数时候我们应用
最后总结,Python 3.10 的一个关键特性就是结构化模式匹配。
链接:
永久链接 https://yanbin.blog/python-3-10-new-features/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
Python 3.7 所带来的新特性
- breakpoint()
- 数据类(@dataclass)
- 类型提示强化和延迟注解求值
- 时间精度的提高
- 保证字典的顺序
- async 和 await 成为关键字
- asyncio.run() 简化事件循环
- 上下文变量(ContextVar) - 可实现 ThreadLocal 和 SLF4J 的 MDC 功能
体验一下 Python 3.8 带来的主要新特性
- 赋值表达式(:=) -- Walrus Operator
- 可限定只按位置传递参数
- 更精确的类型提示(增强了 Type Hints)
- 用 f-strings 进行简单的调试(f"{name = }" 输出 name = 'Eric'
- 新模块 importlib.metadata
- Math 和 Statistics 函数
- 更聪明的警告信息
Python 3.9 新特性回顾
- 字典的并集操作( d1 | d2)
- 删除字符串前缀和后缀的函数(removeprefix(), removesuffix())
- 更简单的泛型提示(list[str], 而不用 typing.List[str])
- DateTime 新增时区支持(不再依赖 pytz)
- shutdown() Executor 时可取消待处理任务
- random.Random.randbytes() 生成随机字节
- typing.Annotated 类型提示(distance: Annotated[float, 'feet'] 类型加注解提示)
回顾完上面后,开始学习 Python 3.10 的新特性, 参考 What's New In Python 3.10
带圆括号的上下文管理器
使用 Python 3.9.12 的 with 就可以一次管理个资源,如1with (open('test.txt') as f1, # 外加圆括号后其中语句可分多行写
2 open('test.txt') as f2):
3 ...
4
5# 或者
6with open('test.txt') as f1, open('test.txt') as f2): # 只能写在同一行
7 ...更友好的错误提示
像[1, , {a:2, 2: 会提示 '[' was never closed 和 '{" was never closed, 而不是笼统的说 invalid syntax。还有更多的更聪明的错误提示,没必要一一列出,反正也不影响如何书写代码,只是看到了错误信息容易定位错误,多用,谁用谁知道
结构化模式匹配
Python 没有 switch 语句,所以不得不用if...elif..else 语句,不过现在 Python 3.10 从 Scala 学来了更高级的 match...case 语句。模式匹配功能很强大,展开来值得单独写一篇匹配字面值
1def http_error(status):
2 match status:
3 case 400:
4 print("Bad request")
5 case 404:
6 return "Not found"
7 case 401 | 402 | 403:
8 return "Not allowed"
9 case _:
10 return "Unknown"
11
12print(http_error(400))
13print('--')
14print(http_error(404))
15print(http_error(401))
16print(http_error(405))Bad requestPython 的
None
--
Not found
Not allowed
Unknown
match...case 是语句,而非表达式,所以它本身不能赋值给变量的。每个 case 后相当于自动加上了
break 语句, case _: 相当于 case default:, case 后的多个匹配可用 | 连接。没有
case _: 的 match 相当于什么也没匹配到,是一个 no-op 操作行为,如果以上函数中拿掉 case _:, http_error(405) 得到的就是 None更强大的匹配功能还在后头,比如对类型,类型值的匹配,首先看它如何匹配一个元组,并获取其中的值
1def test(point):
2 match point:
3 case (0, 0):
4 print("Origin")
5 case (0, y):
6 print(f"{y = }")
7 case ():
8 print("Is a tuple")
9
10test(())
11test((0,3))
12test((0,0))Is a tuple进一步延伸,可以有更丰富的匹配功能
y = 3
Origin
- case []: 是一个列表
- case [1, 3, a]: 匹配前两个值为 1, 3 的三元素列表,第三个元素赋给 a 变量
- case [1,2, *a]: 结合 Python 的集合拆解功能, 这里匹配至少两元素的列表,头两元素为 1, 2, 其余元素赋给 a 列表
- case Point(x=0, y=0): 假如声明了类
class Point: x: int; y: int, 它则可匹配到 x=0, y=0 的 Point 对象, - case Point(x=xvar, y=yvar): 匹配 Point 类型,并捕获 x, y 的值,用
xvar和yvar引用 x, y 的值 - case Point(): 匹配 Point 类型,相当于
isinstance(p, Point) - case [Point(0,0)]: 嵌套匹配 Point(0,0) 单元素列表
如果用 case Point(x,y), 则会报错
case Point(x, y):因为在 Point 中 x, y 是没有顺序的, 相当于是按名赋值的,只要给 Point 声明一个
TypeError: Point() accepts 0 positional sub-patterns (2 given)
__match_args__ 则可用 Point(x, y) 进行匹配,完整代码如下 1class Point:
2 __match_args__ = ("x", "y")
3
4 def __init__(self, x, y):
5 self.x = x
6 self.y = y
7
8def test(point):
9 match point:
10 case Point(x, y):
11 print(f'{x = }, {y = }')
12
13p = Point(1, 2)
14test(p)x = 1, y = 2
- case Point(x, y) if x == y: 加约束条件的匹配
- case {"name": b, "id": 1}: 匹配字典
- case {"name": b, **rest}: 匹配字典剩余的项
- case (Point(x1, y1, Point(x2, y2) as p2): 用
as关键字捕获子模式 - 匹配枚举值
1from enum import Enum
2class Color(Enum):
3 RED = 0
4 GREEN = 1
5
6match color:
7 case Color.RED:
8 ...EncodingWarning 提示
增加 -X warn_default_encoding 选项和 PYTHONWARNDEFAULTENCODING 来启用相应警告,用于定位由于打开文件编码引起的问题新的联合类型提示
Python 3.10 前的联合类型提示用 typing.Unionnumber: Union[int, float]现在直接用
|number: int | float在进行实例类型判断时也可以用
|, 如isinstance(1, int | str)有
| 的写法,对于def foo(value: str | None):...就不用写成
def foo(value: Union[str, None]):...或
def foo(value: Optional[str]):...
类型别名
Python 3.10 之前类型别名和使用是这样写1StrCache = 'Cache[str]'
2cache: StrCache = {}StrCache 看起就像是一个值为 Cache[str] 的字符串变量,也确实是,用 type(StrCache) 得到的就是 <class 'str'>.Python 3.10 的写法让它看起来更像是一个类型
1from typing import TypeAlias
2
3StrCache: TypeAlias = 'Cache[str]'
4cache: StrCache = {}1cache: 'Cache[str]' = {}
2# Python 解释器看到的其实只是
3cache = {}1Card: TypeAlias = tuple[str, str]
2card: Card = ("J", "Heart")更严格的 zip() 函数
zip() 函数作用于两个序列,生成 tuple 序列,Python 不要求两个序列等长,只以短序列为准,长序列多出部分被忽略1>>> list(zip([1], [2,3]))
2[(1, 2)]
3>>> list(zip(['a', 'b'], [1]))
4[('a', 1)]
5>>> list(zip(['a'], [1, 2]))
6[('a', 1)]zip() 函数想要完全配对。所以在 Python 3.10 中加入了 strict 参数1>>> list(zip(['a'], [1, 2], strict=True))
2Traceback (most recent call last):
3 File "<stdin>", line 1, in <module>
4ValueError: zip() argument 2 is longer than argument 1链接:
永久链接 https://yanbin.blog/python-3-10-new-features/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。