Python 3.12 新特性

继续感受新特性系列,这次看看于 2023 年 10 月 2 日发布的 Python 3.12 给我们带来了什么新特性。Python 3.14 预计在今年 10 月份推出,一定要对每年一个正式版的新东西有所了解。依旧是由官方的 What's New In Python 3.12 阅读进行展开。

Python 3.12 从编程上的观感变化不大,主要是移除了 distutils, 增加了 f-stringstype 提示,其他对诸如迭代推导等的字节码优化,对性能的提示是不具有直接感受的。

Python 3.12 移除了 distutils(Distribution Utilities)

distutils 是一个 Python 内建的构建,打包和分布 Python 模块/包的工具集,其实对于多数应用开发人员对此也是感的。能与此能顺利建立关联的就是有些 Python 项目中的那个 setup.py 文件,那也是史前的产物。随着 Python 的快速流行,Python 的包管与构建工具也多了起来, 像 Poetry, PDMuv, 尤其是 uv(Rust 编写的) 的闪电速度及全能表现有望成为 Python 界的 Maven。

注:提到 uv 时还应留意 AStRAL 的另外两个工具,RUFF: 用 Rust 写的轻量级,极速的 Python linter 工具; ty: 也是用 Rust 写的极速 Python 类型检查与 language server 工具。并且 uvx 命令将会与我们相伴随。又从 PyCharm 中看到一个新的 Python 工具链 Hatch

distutils 移除后会给我们带来什么影响呢?对于老旧的依然使用 setup.py 的项目要升级到 Python 3.12 就要把 setup.py 中的

from distutils.core import setup

替换为

from setuptools import setup

所以 setuptools 是 distutils 的替代品,它功能更齐全,与现代工具链完全兼容,支持依赖自动安装,支持插件和自定义命令和 pyproject.toml 配置,它还是要用 twine 来上传包。不过使用了 Poetry, PDM 或 uv 的来管理项目的话,连 setuptools 是什么都不用去在意。

对于 python3.11 -m venv venv311 和 python3.12 -m venv venv312 生成的虚拟环境目录,bin 目录没有区别,区别在于 site-packages 中少了些东西

关于 distutils 的内容就说这些了,下面一个新特性是

f-strings 的增强

首先顺便回顾一下 f-strings 的比较全方位的功能。

f-strings 自 Python 3.6 推出之后,持续在增强功能,最初只是 'f' 或 'F' 前缀字符串中 {} 可用变量或表达式。3.8 添加了 =, !s, !r, !a 的支持,假设 o=3

f-strings 中的冒号 : 会调用 __format__() 函数

比如可以自定义 __format__() 函数

输出

formatted by test

单行表达式,f"{x if x > 0 else y}". 或者下面的语法

其实 {} 中间罗列多个相当于是一价目 tuple, 完整的语法是

想像一下某个函数接受参数类型为 tuple 时,我们只有一个元素时就要写成以下调用形式

回顾完了,开始 Python 3.12 对 f-strings 的增强

f-strings 中可包含与外层相同的引号

好似最外层的引号(或{})让中间的相同的引号自动进行的转义

或者像官方文档中的例子,实现 f-strings 嵌套

f-strings 大括号可写成多行

实际上也是因了上条的原因,f-strings 能够匹配前后两个大括号,所以大括号中间可以换行,还能加上注释

输出

versions: 1, 2

f-strings 可包含 \ 转义符

在 Python 3.12 之前,即使避开用外层相同的引号也不能用 \ 转义符

以上代码在 Python 3.11 中报错

SyntaxError: f-string expression part cannot include a backslash

在 Python 3.12 中通过,就是全用相同的引号都行

同时包含 \ 和 {} 的例子

输出为

This is the playlist: major♥ minor

\N{BLACK HEART SUIT} 就是

type 表达式,即类型别名

Python 3.12 引入了一个像 C/C++ typedef 那样语法来定义类型

那么我们使用 Point

回顾一下我们在 Python 3.12 以前不显式用  class 创建类时可以怎么定义类型

namedtuple

可用属性 x, y 来访问

TypedDict

本质上还是一个 Dict

泛型实现更简单

以前实现一个 Python 的泛型类要用到 TypeVar, Generic

现在 Python 3.12 直接上 T, 像是 Java 泛型的写法,上面的代码可简化为

省去了使用 Cache 类的代码。

type 语句中用泛型,也是直接用表示类型的字符(串)

可结合 Java 的泛型语法来理解。

其他 typing 相关的新特性

用 TypedDict 来准确的注解 **kwargs

上面刚回顾了 TypedDict,这就要派上用场,**kwargs 的参数太随意了,只知道是可以用 a=?, b=?, c=? 来传递的 keyword 类型的参数,再就没有具体的限制了。而用 TypedDict 注解 **kwargs 就能被类型系统或 IDE 识别出具体能接受参数的 keywaord

直接用官方的例子

现在试图调用

用 mypy 就能检验出参数错误

test.py:7: note: "foo" defined here
test.py:10: error: Unexpected keyword argument "xyz" for "foo" [call-arg]
Found 1 error in 1 file (checked 1 source file)

ty check test.py,尚不识别 TypeDict 的约束,提示 All checked passed!

类似 Java 的 @override 的 typing.override() 装饰器

和 Java 中的 @override 是一样的意思,表示覆盖父类中的方法

对于父类中不存在的方法应用了 @override 也同能被 mypy 检测出来。

引入 typing.override  时注意到还有 typing.overload,它可用来模拟出 Python 的重载方法,然而 @overload 装饰的方法却不能有实现,只用能声明支持的重载方法签名,实现要统一写在那个同名的但没有 @overload 装饰的方法中。此处不作引申。

可通过 python -m sqlite3 命令进入 sqlite shell

本地没有安装独立的 sqlite3, 用 Python 自带的就行

python -m uuid 命令产生 uuid

连安装 uuid, 或 guid 命令都省了,Python 提供的快捷工具还真不少。

python -m uuid
1adc93b0-cea0-42da-ba1d-94a9fbc67d43

用 -u {uuid1,uuid3,uuid4,uuid5} 参数选择 uuid 的类型

其他

其他更友好的错误建议提示,推导的内联优化, isinstance(), asyncio 的性能提升。每个解释器单独的 GIL(全局解释锁),这可让子进程更有效的使用多核 CPU。

type-except* 处理整个 ExceptionGroup 并抛出另一个异常时,该异常不再包装为 ExceptionGroup.

新方法 pathlib.Path.walk(), 类似于 os.walk(), 看来有些 os 的操作可考虑用 pathlib 中类似方法。

 

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

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

Subscribe
Notify of
guest

1 Comment
Inline Feedbacks
View all comments
天天下载
天天下载
15 days ago

很棒的网站,感谢分享