Python 3.11 关键新特性之其他
前面整一篇只讲了 Python 3.11 的新语法特性,异常组与
从 Python 3.11 开始新加了对 TOML 配置文件的编程接口,像使用 JSON 和 Pickle 一样的 load() 和 loads() 反序列方法,没有序列化方法
data 得到的是一个 dict[str, Any]。tomllib.loads("<toml_str>") 是从一个 TOML 配置字符串加载为字同典。
tracebacks 中用波浪线显示更精确的错误代码的位置,而不仅指示到错误代码行,这个不影响到编程,方便于 Debug
首先看新加的参数 -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 时加上
设置了 PYTHONSAFEPATH 为非空值时,相当于是 python 带了
相当于是 python -P demo.py
默认 key 是 Required, 如
这里学到了一个新技能,以前想要一个模型类的话,选择是 @dataclass, 或 NamedTuple, 显然用 TypeDict 要方便。
Python 解析不过
因为此时
但我们尽量避免用字符串作为类型注解,因为字符串是动态的,在 Python 3.11 中引入的
这有什么意义呢?在静态代码扫描时确保传入的字符串是安全的,比如不允许通过动态的方式构建一个不安全的 SQL 语句
最后学一个 Python 3.9 就支持的在 for 语句中用
输出
我们在阅读 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 执行
Python 3.11 还没有使用 JIT 编译 永久链接 https://yanbin.blog/python-3-11-key-new-features-others/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
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() 反序列方法,没有序列化方法
1import tomllib
2
3with open("pyproject.toml", 'rb') as f:
4 data = tomllib.load(f)tracebacks 中用波浪线显示更精确的错误代码的位置,而不仅指示到错误代码行,这个不影响到编程,方便于 Debug
新的 -P 命令行参数和环境变量 PYTHONSAFEPATH 避免了潜在不安全的路径添加到 sys.path 中
sys.path 中的列表告诉 Python 解析器从哪里加载脚本或包,模块,见 Python 的模块搜索路径 中有对它详尽的描述, 以及可通过环境变量 PYTHONPATH 附加模块的搜索路径。首先看新加的参数 -P 的效果,假如有一段打印 sys.path 内容的代码 demo.py
1import sys
2print('\n'.join(sys.path))1venv_311/bin/python demo.py
2/Users/yanbin/Workspaces/test-python
3/opt/homebrew/Cellar/python@3.11/3.11.13/Frameworks/Python.framework/Versions/3.11/lib/python311.zip
4/opt/homebrew/Cellar/python@3.11/3.11.13/Frameworks/Python.framework/Versions/3.11/lib/python3.11
5/opt/homebrew/Cellar/python@3.11/3.11.13/Frameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload
6/Users/yanbin/Workspaces/test-python/venv_311/lib/python3.11/site-packages带上 -P 参数执行 python -P demo.py
1venv_311/bin/python -P demo.py
2/opt/homebrew/Cellar/python@3.11/3.11.13/Frameworks/Python.framework/Versions/3.11/lib/python311.zip
3/opt/homebrew/Cellar/python@3.11/3.11.13/Frameworks/Python.framework/Versions/3.11/lib/python3.11
4/opt/homebrew/Cellar/python@3.11/3.11.13/Frameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload
5/Users/yanbin/Workspaces/test-python/venv_311/lib/python3.11/site-packages对于 python -m module 和 python -c code 或 python 进入 REPL 时加上
-P 参数也能实现一样的阻止当前目录作为模块搜索路径。设置了 PYTHONSAFEPATH 为非空值时,相当于是 python 带了
-P 参数,例如1PYTHONSAFEPATH=xx venv_311/bin/python demo.py
2/opt/homebrew/Cellar/python@3.11/3.11.13/Frameworks/Python.framework/Versions/3.11/lib/python311.zip
3/opt/homebrew/Cellar/python@3.11/3.11.13/Frameworks/Python.framework/Versions/3.11/lib/python3.11
4/opt/homebrew/Cellar/python@3.11/3.11.13/Frameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload
5/Users/yanbin/Workspaces/test-python/venv_311/lib/python3.11/site-packages新增了 TypeVarTuple 支持 Variadic 泛型
TypedDict 中可表示某个 key 是必须还是可选
1from typing import TypedDict, NotRequired
2
3class Movie(TypedDict):
4 title: str
5 year: NotRequired[int]
6
7
8m1: Movie = {"title": "Black Panther", "year": 2018}
9m2: Movie = {"title": "Star Wars"}
10m3: Movie = {"year": 2022} # TypedDict 'Movie' has missing key: 'title'title: str 相当于是 title: Required[str]. 但 TypedDict 毕竟是 typing 的范畴,Python 解析器执行时没有强制,只是通不过像 mypy 那种工具的关。这里学到了一个新技能,以前想要一个模型类的话,选择是 @dataclass, 或 NamedTuple, 显然用 TypeDict 要方便。
用 Self 来表示方法返回一个自身实例
比如一个方法返回自身实例 self, 试图下面那样写1class MyLock:
2 def __enter__(self) -> MyLock:
3 self.lock()
4 return self1 def __enter__(self) -> MyLock:
2 ^^^^^^
3NameError: name 'MyLock' is not definedMyLock 还不存在,但可以用引号扩起来1def __enter__(self) -> "MyLock":Self 来解决1from typing import Self
2
3class MyLock:
4 def __enter__(self) -> Self:
5 self.lock()
6 return selfLiteralString 注解规定函数参数只接受字面常量字符串
字符串变量就不行 1import sys
2from typing import LiteralString
3
4def run_query(name: LiteralString):
5 pass
6
7run_query("select * from students")
8str_var=f"select * from students where {sys.argv[1]}"
9run_query(str_var) # Expected type 'LiteralString', got 'str' instead
10
11def bar(xxx: LiteralString):
12 run_query(xxx) # 这是合法的,因为 xxx 也是一个 LiteralStringselect * from students where 1=1; delete from students
PEP 681: Data class transforms
dataclass_transform 可用过创建某些共性的模型类,应该可增强 dataclass 的行为。这里打个标记,以后真有需求时再详细研究。最后学一个 Python 3.9 就支持的在 for 语句中用 * 星号的语法
1for a, b, c in [(1, 2, 3), (4, 5, 6)]:
2 print(a, b, c)
3
4print('---------')
5
6for a, *b in [(1, 2, 3), (4, 5, 6)]:
7 print(a, b)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) 结尾的情况只列出目录, 比如下面的代码
1from pathlib import Path
2
3for p in Path(".").glob('*/'):
4 print(p, p.is_dir())venv_310/bin/python demo.pyPython 3.11 执行
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
venv_311/bin/python demo.py增加了 ZipFile.mkdir() 在 ZIP 文件内部创建目录
venv_311 True
venv_310 True
.mypy_cache True
venv_312 True
venv_313 True
.idea True
Python 3.11 还没有使用 JIT 编译 永久链接 https://yanbin.blog/python-3-11-key-new-features-others/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。