Python 3.11 关键新特性之其他

前面整一篇只讲了 Python 3.11 的新语法特性,异常组与 except*, 这篇说其他的。

可为异常添加备注

在 BaseException 上新加了一个实例方法 add_note(self, note),在捕获到异常后可进一步润色而无需创建一个新的异常再次抛出。

内置 tomllib 支持 TOML 配置文件

TOML 是 Tom's Obvious Minimal Language, 像 INI 文件,但表述性更强,支持丰富的数据类型。现代新型的 Python 项目依赖管理构建工具都使用了 pyproject.toml 文件,如 Poetry, uv, 以及 PDM。pyproject.toml 在 Python  3.6 就引入了,见 PEF 518,但似乎一直被顽固的 Python -m venv 忽略。

从 Python 3.11 开始新加了对 TOML 配置文件的编程接口,像使用 JSON 和 Pickle 一样的 load() 和 loads() 反序列方法,没有序列化方法

data 得到的是一个 dict[str, Any]。tomllib.loads("<toml_str>") 是从一个 TOML 配置字符串加载为字同典。

tracebacks 中用波浪线显示更精确的错误代码的位置,而不仅指示到错误代码行,这个不影响到编程,方便于 Debug

新的 -P 命令行参数和环境变量 PYTHONSAFEPATH 避免了潜在不安全的路径添加到 sys.path 中

sys.path 中的列表告诉 Python 解析器从哪里加载脚本或包,模块,见 Python 的模块搜索路径 中有对它详尽的描述, 以及可通过环境变量 PYTHONPATH 附加模块的搜索路径。

首先看新加的参数 -P 的效果,假如有一段打印  sys.path 内容的代码 demo.py

不带 -P 参数执行 python demo.py

看到当前路径添加在了 sys.path 的最前端

带上 -P 参数执行  python -P demo.py

这样就防止了把当前路径添加进 sys.path, python 解析器只读取当前路径上的 demo.py,而避免了加载当前路径中的其他可能不安全的模块,比如在当前路径中创建与其他库同名的模块,以达到替换实现的目的。

对于 python -m module 和 python -c code 或 python 进入 REPL 时加上 -P 参数也能实现一样的阻止当前目录作为模块搜索路径。

设置了 PYTHONSAFEPATH 为非空值时,相当于是 python 带了  -P 参数,例如

相当于是 python -P demo.py

新增了 TypeVarTuple 支持 Variadic 泛型

TypedDict 中可表示某个 key 是必须还是可选 

默认 key 是 Required, 如 title: str 相当于是 title: Required[str]. 但 TypedDict 毕竟是 typing 的范畴,Python 解析器执行时没有强制,只是通不过像 mypy 那种工具的关。

这里学到了一个新技能,以前想要一个模型类的话,选择是 @dataclass, 或 NamedTuple, 显然用 TypeDict 要方便。

用 Self 来表示方法返回一个自身实例

比如一个方法返回自身实例 self, 试图下面那样写

Python 解析不过

因为此时 MyLock 还不存在,但可以用引号扩起来

但我们尽量避免用字符串作为类型注解,因为字符串是动态的,在 Python 3.11 中引入的 Self 来解决

LiteralString 注解规定函数参数只接受字面常量字符串

字符串变量就不行

这有什么意义呢?在静态代码扫描时确保传入的字符串是安全的,比如不允许通过动态的方式构建一个不安全的 SQL 语句

select * from students where 1=1; delete from students

PEP 681: Data class transforms

dataclass_transform 可用过创建某些共性的模型类,应该可增强 dataclass 的行为。这里打个标记,以后真有需求时再详细研究。

最后学一个 Python 3.9 就支持的在 for 语句中用 * 星号的语法

输出

1 2 3
4 5 6
---------
1 [2, 3]
4 [5, 6]

总结

Python 3.11 从语言上好像没带来太亮眼的新特性,只是到了发布周期必须出一个版本而已。最主要的就是增加了 Exception Group 的 except* 语法,然而似乎应用性不大,如果 except 和 except* 搞混了,不会有语法错误,但极有可能引入替在的 Bug。

我们在阅读 What's New In Python 3.11 的时候, Improved Modules 部分虽不是重头戏,最好也别放过。其中描述了哪些 API 已删除,在使用 IDE 写 Python 代码时根据选择的 Python 版本会被识别出来。但新加的 API 还是很有用处的,如

datetime.UTC,再也不用写成  datetime.timezone.utc 了

EnumMeta 改成了 EnumType

新增了 StrEnum 用了专门表示字符串类型的枚举

使用  gzip.compress() 时指定 mtime=0 的话(即 gzip.compress(data=..., mtime=0)),压缩变快,因为它用调用 zlib.compress() 操作

math 库方面,新增了 math.exp2() 平方操作,因为太常用了。新增了 math.cbrt() 立方根.

新增了 operator.call 操作,如果一个 obj 是 callable, obj(*args, **kwargs) 可以写成 operator.call(obj, *args, **kwargs)

pathlib 的 glob() 和 rglob() 在 pattern 以路径分隔符(os.sep 或 os.altsep) 结尾的情况只列出目录, 比如下面的代码

Python 3.10 执行

venv_310/bin/python demo.py
venv_311 True
venv_310 True
test-python.iml False
test.py False
.mypy_cache True
.gitignore False
venv_312 True
demo.py False
venv_313 True
.idea True

Python 3.11 执行

venv_311/bin/python demo.py
venv_311 True
venv_310 True
.mypy_cache True
venv_312 True
venv_313 True
.idea True

增加了 ZipFile.mkdir() 在 ZIP 文件内部创建目录

Python 3.11 还没有使用 JIT 编译

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

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

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments