time
在 Unix 上,如果有可能,
time.sleep()
现在将使用clock_nanosleep()
或nanosleep()
函数,其精度为 1 纳秒 (10-9 秒),而不是使用精度为 1 微秒 (10-6 秒) 的select()
。 (由 Benjamin Szőke 和 Victor Stinner 在 bpo-21302 [https://bugs.python.org/issue?@action=redirect&bpo=21302] 中贡献。)在 Windows 8.1 或更新版本上,现在
time.sleep()
会使用一个基于 高精度计时器 [https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/high-resolution-timers] 的可等待计时器,其精度为 100 纳秒 (10-7 秒)。 在之前版本中,其精度为 1 毫秒 (10-3 秒)。 (由 Benjamin Szőke, Donghee Na, Eryk Sun 和 Victor Stinner 在 bpo-21302 [https://bugs.python.org/issue?@action=redirect&bpo=21302] 和 bpo-45429 [https://bugs.python.org/issue?@action=redirect&bpo=45429] 中贡献。)
tkinter
- 增加了将 Tcl 库的准确版本号作为类似
sys.version_info
的命名元组返回的方法info_patchlevel()
。 (由 Serhiy Storchaka 在 gh-91827 [https://github.com/python/cpython/issues/91827] 中贡献。)
traceback — 回溯
增加了
traceback.StackSummary.format_frame_summary()
以允许用户重载要在回溯中出现哪些帧,以及要如何格式化它们。 (由 Ammar Askar 在 bpo-44569 [https://bugs.python.org/issue?@action=redirect&bpo=44569] 中贡献。)增加了
traceback.TracebackException.print()
,该函数可将TracebackException
实例格式化打印到一个文件。 (由 Irit Katriel 在 bpo-33809 [https://bugs.python.org/issue?@action=redirect&bpo=33809] 中贡献。)
typing
主要的变化,请参阅 有关类型提示的新增特性。
增加了
typing.assert_never()
和typing.Never
。typing.assert_never()
适用于要求类型检查器确认某一行代码是不可达的。 在运行时,它会引发AssertionError
。 (由 Jelle Zijlstra 在 gh-90633 [https://github.com/python/cpython/issues/90633] 中贡献。)增加了
typing.reveal_type()
。 它适用于让类型检查器推理出给定表达式的类型。 在运行时它会打印所接收的值的类型。 (由 Jelle Zijlstra 在 gh-90572 [https://github.com/python/cpython/issues/90572] 中贡献。)增加了
typing.assert_type()
。 它适用于让类型检查器确认推理出的给定表达式的类型与给定的类型相匹配。 在运行时它将简单地返回所接收的值。 (由 Jelle Zijlstra 在 gh-90638 [https://github.com/python/cpython/issues/90638] 中贡献。)现在
typing.TypedDict
类型可以是泛型。 (由 Samodya Abeysiriwardane 在 gh-89026 [https://github.com/python/cpython/issues/89026] 中贡献。)现在
NamedTuple
类型可以是泛型。 (由 Serhiy Storchaka 在 bpo-43923 [https://bugs.python.org/issue?@action=redirect&bpo=43923] 中贡献。)允许
typing.Any
子类化。 这适用于避免关联到高度动态类的类型检查器错误,例如 mock 类。 (由 Shantanu Jain 在 gh-91154 [https://github.com/python/cpython/issues/91154] 中贡献。)现在
typing.final()
装饰器可在被装饰的对象上设置__final__
属性。 (由 Jelle Zijlstra 在 gh-90500 [https://github.com/python/cpython/issues/90500] 中贡献。)typing.get_overloads()
函数可被用来内省一个函数的重载。typing.clear_overloads()
可被用来清理一个函数所有的重载。 (由 Jelle Zijlstra 在 gh-89263 [https://github.com/python/cpython/issues/89263] 中贡献。)现在
Protocol
子类的__init__()
方法将被保留。 (由 Adrian Garcia Badarasco 在 gh-88970 [https://github.com/python/cpython/issues/88970] 中贡献。)空元组类型 (
Tuple[()]
) 的表示形式已被简化。 这将影响内省操作,例如get_args(Tuple[()])
现在将被求值为()
而不是((),)
。 (由 Serhiy Storchaka 在 gh-91137 [https://github.com/python/cpython/issues/91137] 中贡献。)通过移除私有
typing._type_check
函数的回调检查放松了类型标注的运行时要求。 (由 Gregory Beauregard 在 gh-90802 [https://github.com/python/cpython/issues/90802] 中贡献。)现在
typing.get_type_hints()
支持将字符串求值为 PEP 585 泛型别名 中的前向引用。 (由 Niklas Rosenstein 在 gh-85542 [https://github.com/python/cpython/issues/85542] 中贡献。)typing.get_type_hints()
将不再添加Optional
到形参并以None
作为默认值。 (由 Nikita Sobolev 在 gh-90353 [https://github.com/python/cpython/issues/90353] 中贡献。)现在
typing.get_type_hints()
支持与纯字符串化的ClassVar
标注进行求值。 (由 Gregory Beauregard 在 gh-90711 [https://github.com/python/cpython/issues/90711] 中贡献。)typing.no_type_check()
将不再修改外部类和函数。 现在它还会正确地将类方法标记为不进行类型检查。 (由 Nikita Sobolev 在 gh-90729 [https://github.com/python/cpython/issues/90729] 中贡献。)
unicodedata
- Unicode 数据库已更新到 14.0.0 版。 (由 Benjamin Peterson 在 bpo-45190 [https://bugs.python.org/issue?@action=redirect&bpo=45190] 中贡献。)
unittest
- 增加了
TestCase
类的enterContext()
和enterClassContext()
方法,IsolatedAsyncioTestCase
类的enterAsyncContext()
方法和unittest.enterModuleContext()
函数。 (由 Serhiy Storchaka 在 bpo-45046 [https://bugs.python.org/issue?@action=redirect&bpo=45046] 中贡献。)
venv
- 当新的 Python 虚拟环境被创建时,将使用 venv sysconfig 安装方案 来确定环境内部的路径。 当 Python 在虚拟环境中运行时,同一个安装方案将被设为默认。 这意味着下游分发方可以修改默认的 sysconfig 安装方案而不会改变虚拟环境的行为。 同样会创建新的虚拟环境的第三方代码也应当这样做。 (由 Miro Hrončok 在 bpo-45413 [https://bugs.python.org/issue?@action=redirect&bpo=45413] 中贡献。)
warnings
warnings.catch_warnings()
现在接受warnings.simplefilter()
的参数,这提供了一种在局部忽略警告或将其转为错误的更精确方式。 (由 Zac Hatfield-Dodds 在 bpo-47074 [https://bugs.python.org/issue?@action=redirect&bpo=47074] 中贡献。)
zipfile
增加了为在
ZipFile
的目录和文件头中读取元数据指定成员名称编码格式的支持。 (由 Stephen J. Turnbull 和 Serhiy Storchaka 在 bpo-28080 [https://bugs.python.org/issue?@action=redirect&bpo=28080] 中贡献。)增加了
ZipFile.mkdir()
用于在 ZIP 归档中新建目录。 (由 Sam Ezeh 在 gh-49083 [https://github.com/python/cpython/issues/49083] 中贡献。)为
zipfile.Path
增加了stem
,suffix
和suffixes
。 (由 Miguel Brito 在 gh-88261 [https://github.com/python/cpython/issues/88261] 中贡献。)
性能优化
本节列出的特定优化均不依赖于 更快的 CPython 项目,后者将在其专属章节中列出。
编译器现在将优化只包含格式代码
%s
,%r
和%a
的字符串字面值中的简单 printf 风格 % 格式化 并使其速度与对应的 f-string 表达式一样快。 (由 Serhiy Storchaka 在 bpo-28307 [https://bugs.python.org/issue?@action=redirect&bpo=28307] 中贡献。)整除运算 (
//
) 已进行了更好的编译器微调。 在 x86-64 上现在将int
除以小于2**30
的值时能够提速 20%。 (由 Gregory P. Smith 和 Tim Peters 在 gh-90564 [https://github.com/python/cpython/issues/90564] 中贡献。)sum()
现在对小于2**30
的整数运算可提速将近 30%。 (由 Stefan Behnel 在 gh-68264 [https://github.com/python/cpython/issues/68264] 中贡献。)列表大小调整针对常见场景进行了优化,对于
list.append()
可提速 ≈15% 而对于简单的 list comprehension 可提速 20-30%。 (由 Dennis Sweeney 在 gh-91165 [https://github.com/python/cpython/issues/91165] 中贡献。)字典在所有键均为 Unicode 对象时将不保存哈希值,以缩减
dict
的大小。 例如,sys.getsizeof(dict.fromkeys("abcdefg"))
在 64 位平台上将从 352 字节缩减为 272 字节(减小 23%)。 (由 Inada Naoki 在 bpo-46845 [https://bugs.python.org/issue?@action=redirect&bpo=46845] 中贡献。)现在使用
asyncio.DatagramProtocol
通过 UDP 传输大文件时速度将有成数量级的提升,对于 ≈60 MiB 的文件将可提速 100 倍以上。 (由 msoxzw 在 gh-91487 [https://github.com/python/cpython/issues/91487] 中贡献。)现在
math
中的函数comb()
和perm()
对于大参数可提速 ≈10 倍(对于越大的 k 值提速幅度越大)。 (由 Serhiy Storchaka 在 bpo-37295 [https://bugs.python.org/issue?@action=redirect&bpo=37295] 中贡献。)现在
statistics
中的函数mean()
,variance()
和stdev()
将会直接消耗迭代器而不是先将它们转换为list
。 这将使速度翻倍并能节省大量内存。 (由 Raymond Hettinger 在 gh-90415 [https://github.com/python/cpython/issues/90415] 中贡献。)现在
unicodedata.normalize()
将在固定时间内正规化纯 ASCII 字符串。 (由 Donghee Na 在 bpo-44987 [https://bugs.python.org/issue?@action=redirect&bpo=44987] 中贡献。)
更快的 CPython
平均而言 CPython 3.11 比 CPython 3.10 快 25% [https://github.com/faster-cpython/ideas#published-results],该数据是用 pyperformance [https://github.com/python/pyperformance] 基准测试套件测得的,基于 Ubuntu Linux 上的 GCC 编译版。 根据工作负载的不同,总的提速效果可达 10-60%。
本项目聚焦于 Python 的两个主要领域: 更快的启动 和 更快的运行时。 本项目未涉及的优化将在 性能优化 中单独列出。
更快的启动
冻结导入 / 静态代码对象
Python 会将 bytecode 缓存到 pycache 目录以加快模型加载的速度。
在 3.10 版本时,Python 模块执行类似于这样:
- 读取 __pycache__ -> 反 marshal -> 堆分配的代码对象 -> 求值
在 Python 3.11 中,对 Python 启动具有关键影响的核心模块已被“冻结”。 这意味着它们的 代码对象 (及字节码) 将由解释器静态地分配。 这使得模块执行过程的步骤减少为:
- 静态分配的代码对象 -> 求值
现在 Python 3.11 解释器启动加快了 10-15%。 这对使用 Python 的短期运行程序具有显著的影响。
(由 Eric Snow, Guido van Rossum 和 Kumar Aditya 在许多问题事件中贡献。)
更快的运行时
开销更低、更为惰性的 Python 帧
存放执行信息的 Python 帧会在 Python 调用一个 Python 函数时被自动创建。 下面是新帧的优化操作:
优化改进了帧创建进程。
通过大量重用 C 栈上的帧空间来避免内存分配。
将内部帧结构优化为仅包含关键信息。 在此之前的帧保存有额外的调试和内存管理信息。
现在旧式的 帧对象 仅在调试器或 Python 内省函数如 sys._getframe()
和 inspect.currentframe()
发出请求时才会被创建。 对于大多数用户代码,将不会创建任何帧对象。 因此,几乎所有 Python 函数调用都有显著的提速。 我们在 pyperformance 中测得了 3-7% 的提速。
(由 Mark Shannon 在 bpo-44590 [https://bugs.python.org/issue?@action=redirect&bpo=44590] 中贡献。)
内联的 Python 函数调用
在 Python 函数调用期间,Python 将调用一个评测 C 函数来解读该函数的代码。 这会有效地将纯 Python 递归限制在 C 栈的安全范围以内。
在 3.11 中,当 CPython 检测到 Python 代码调用了另一个 Python 函数时,它会设置一个新帧,并“跳转”到新帧内部的新代码。 这可以避免全部调用 C 解析函数。
大多数 Python 函数调用现在将不消耗任何 C 栈空间,这提升了它们的速度。 在简单的递归函数如斐波那契或阶乘函数中,我们测得了 1.7x 的提速。 这还意味着递归函数能够递归得更深(如果用户通过 sys.setrecursionlimit()
提升了递归限制的话)。 我们在 pyperformance 中测得了 1-3% 的提升。
(由 Pablo Galindo 和 Mark Shannon 在 bpo-45256 [https://bugs.python.org/issue?@action=redirect&bpo=45256] 中贡献。)
PEP 659:专门化自适应解释器
PEP 659 [https://peps.python.org/pep-0659/] 是 Faster CPython 项目的关键部分之一。 基本理念在于虽然 Python 是一种动态语言,但大部分代码都存在对象和类型极少发生变化的区域。 这一理念被称为 类型稳定性。
在运行时,Python 将尝试在所执行的代码中寻找常见模式和类型稳定性。 然后 Python 将把当前的操作替换为更加专门化的操作。 这种专门化的操作使用仅对这些应用场景/类型来说可用的快速路径,它们的性能通常都会超过其泛用型的对应物。 这还带来了名为 内联缓存 的另一项理念,即 Python 会将高消耗的操作的结果直接缓存在 bytecode 中。
这个特化程序还会将特定的常见指令对合并为一条超级指令,减少执行期间的开销。
Python 将只特化(会被多次执行的)“热门”代码。 这可以防止 Python 在只执行一次的代码上浪费时间。 Python 还可以在代码过于动态或用法发生变化时取消特化。 特化会定期地尝试,而特化尝试的开销也不高,这使得特化能够适应新的环境改变。
(PEP 由 Mark Shannon 撰写,部分想法由 Stefan Brunthaler 提供。 请参阅 PEP 659 [https://peps.python.org/pep-0659/] 了解详情。 由 Mark Shannon 和 Brandt Bucher 实现,并由 Irit Katriel 和 Dennis Sweeney 提供了额外的帮助。)
运算 | 形式 | 专门化 | 运行加速(最高) | 贡献者 |
---|---|---|---|---|
双目运算 |
x + x
x - x
x * x
|
常见类型如 int , float 和 str 的双目加法、乘法和减法将采用针对其下层类型专门定制的快速路径。
| 10% | Mark Shannon, Donghee Na, Brandt Bucher, Dennis Sweeney |
下标 |
a[i]
|
对容器类型如 list , tuple 和 dict 的下标操作将直接索引下层数据结构。
对自定义 __getitem__() 的下标操作也是采用类似于 内联的 Python 函数调用 的内联方式。
| 10-25% | Irit Katriel, Mark Shannon |
存储下标操作 |
a[i] = z
| 类似于上述的下标操作专门化。 | 10-25% | Dennis Sweeney |
调用 |
f(arg)
C(arg)
|
对常用内置 (C) 函数和类型如 len() 和 str 的调用将直接调用其下层 C 版本。 这将避免经历内部调用流程。
| 20% | Mark Shannon, Ken Jin |
加载全局变量 |
print
len
| 对象在全局/内置命名空间中的索引会被缓存。 加载全局和内置变量将不需要命名空间查找过程。 | [1] | Mark Shannon |
加载属性 |
o.attr
| 类似于加载全局变量。 属性在类/对象命名空间中的索引会被缓存。 在大多数情况下,加载属性将不需要命名空间查找过程。 | [2] | Mark Shannon |
加载要调用的方法 |
o.meth()
| 方法的实际地址会被缓存。 加载方法现在将不需要命名空间查找过程 — 即使对于具有较长继承链的类来说也是如此。 | 10-20% | Ken Jin, Mark Shannon |
存储属性 |
o.attr = z
| 类似于加载属性的优化。 | 2% 的运行效率 | Mark Shannon |
解包序列 |
*seq
|
针对常见容器如 list 和 tuple 进行了专门化。 避免内部调用流程。
| 8% | Brandt Bucher |
[1] 类似的优化自 Python 3.8 起即已存在。 3.11 针对更多形式进行了专门化并减少了部分开销。
[2] 类似的优化自 Python 3.10 起即已存在。 3.11 针对更多形式进行了专门化。 此外,所有属性加载都应当通过 bpo-45947 [https://bugs.python.org/issue?@action=redirect&bpo=45947] 获得了加速。
杂项
现在由于惰性创建的对象命名空间对象需要的内存将会减少。 它们的命名空间现在还将更自由地共享键。 (由 Mark Shannon 在 bpo-45340 [https://bugs.python.org/issue?@action=redirect&bpo=45340] 和 bpo-40116 [https://bugs.python.org/issue?@action=redirect&bpo=40116] 中贡献。)
实现了“零消耗”的异常,可在未引发任何异常时消除
try
语句的开销。 (由 Mark Shannon 在 bpo-40222 [https://bugs.python.org/issue?@action=redirect&bpo=40222] 中贡献。)解释器中更为简洁的异常表示形式使得捕获异常所需的时间减少了大约 10%。 (由 Irit Katriel 在 bpo-45711 [https://bugs.python.org/issue?@action=redirect&bpo=45711] 中贡献。)
re
的正则表达式匹配引擎已被部分重构,现在会在受支持的平台上使用已计算的 goto(或“线程式代码”)。 因此,Python 3.11 执行 pyperformance 正则表达式基准测试 [https://pyperformance.readthedocs.io/benchmarks.html#regex-dna] 相比 Python 3.10 提速了 10%。 (由 Brandt Bucher 在 gh-91404 [https://github.com/python/cpython/issues/91404] 中贡献。)
常见问题
我要如何编写代码以便应用这些加速?
请编写遵循常见最佳实践的具有 Python 风格的代码;你不需要修改你的代码。 CPython 加速计划会针对我们观察到的常见代码模式进行优化。
CPython 3.11 会使用更多内存吗?
可能不会;我们预期内存占用的增加相比 3.10 不会超过 20%。 这是通过上文提及的帧对象和对象字典内存优化来平衡的。
我没有发现我的运行负载有任何加速。 为什么?
特定代码将不会有明显的收益。 如果你的代码大部时间消耗在 I/O 操作上,或者像 NumPy 那样大部分计算是在 C 扩展库中进行的就将如此。 目前这个项目将只针对纯 Python 的运行负载。
此外,pyperformance 分数是一个几何平均值。 即使在 pyperformance 基准测试内部,特定的基准测试也略有放缓,但其他的基准测试则有将近 2x 的加速!
是否有 JIT 编译器?
没有。 我们还在探索其他优化方式。
关于
CPython 加速项目探索针对 CPython 的优化。 项目主团队由 Microsoft 提供资助来支持全职工作。 Pablo Galindo Salgado 还由 Bloomberg LP 提供资助来兼职该项目。 此外,还有许多贡献者是来自社区的志愿者。
CPython 字节码的改变
字节码现在包含内联缓存条目,它采用新增的 CACHE
指令形式。 许多操作码都预期带有确切数量的缓存,并指示解释器在运行时跳过它们。 被填充的缓存看起来可以像是任意指令,因此在读取或修改包含加速的数据的原始自适应字节码时应当格外小心。
新的操作码
ASYNC_GEN_WRAP
,RETURN_GENERATOR
和SEND
,用于生成器和协程。COPY_FREE_VARS
,这可以避免需要特别的调用方代码来关闭。JUMP_BACKWARD_NO_INTERRUPT
,用于某些不希望处理中断的循环。CHECK_EG_MATCH
和PREP_RERAISE_STAR
,用于处理在 PEP 654 [https://peps.python.org/pep-0654/] 中增加的 新异常组和 except*。PUSH_EXC_INFO
,用于异常处理器。RESUME
,空操作,用于内部追踪、调试和优化检查。
被替换的操作码
被替换的操作码 | 新增的操作码 | 备注 |
---|---|---|
BINARY_*
INPLACE_*
|
BINARY_OP
| 用单个操作码替换所有数值类双目/原地操作码 |
CALL_FUNCTION
CALL_FUNCTION_KW
CALL_METHOD
|
CALL
KW_NAMES
PRECALL
PUSH_NULL
| 对方法的参数变换与关键字参数的处理进行解偶;允许更好的调用特化 |
DUP_TOP
DUP_TOP_TWO
ROT_TWO
ROT_THREE
ROT_FOUR
ROT_N
|
COPY
SWAP
| 栈操纵指令 |
JUMP_IF_NOT_EXC_MATCH
|
CHECK_EXC_MATCH
| 现在会执行检查但不会跳转 |
JUMP_ABSOLUTE
POP_JUMP_IF_FALSE
POP_JUMP_IF_TRUE
|
JUMP_BACKWARD
POP_JUMP_BACKWARD_IF_*
POP_JUMP_FORWARD_IF_*
|
参见 [3]; 针对每个方向的 TRUE , FALSE , NONE 和 NOT_NONE 变种
|
SETUP_WITH
SETUP_ASYNC_WITH
|
BEFORE_WITH
|
with 代码块设置
|
[3]
所有跳转操作码现在都是相对的,包括现有的 JUMP_IF_TRUE_OR_POP
和 JUMP_IF_FALSE_OR_POP
。 该参数现在是相对于当前指令的偏移量而不是绝对位置。
修改/移除的操作码
修改
MATCH_CLASS
和MATCH_KEYS
为不再推入额外的布尔值来指示成功/失败。 而是在失败时推入None
来代替由被提取值组成的元组。修改配合异常使用的操作码以反映它们现在是由栈上的一个条目而非三个条目代表 (参见 gh-89874 [https://github.com/python/cpython/issues/89874])。
移除了
COPY_DICT_WITHOUT_KEYS
,GEN_START
,POP_BLOCK
,SETUP_FINALLY
和YIELD_FROM
。
弃用
本小节列出了已在 Python 3.11 中弃用的 Python API。
已弃用的 C API 将 单独列出。
语言/内置对象
串连
classmethod
描述器(在 bpo-19072 [https://bugs.python.org/issue?@action=redirect&bpo=19072] 中引入)现已被弃用。 它不能再被用来包装其他描述器如property
。 该特性的核心设计存在缺陷并导致了许多下游问题。 要“穿过”一个classmethod
,请考虑使用在 Python 3.10 中添加的__wrapped__
属性。 (由 Raymond Hettinger 在 gh-89519 [https://github.com/python/cpython/issues/89519] 中贡献。)数值大于
0o377
(十进制的 255) 的八进制转义符会产生DeprecationWarning
。 在未来的 Python 版本中,这将引发SyntaxWarning
并最终改为SyntaxError
。 (由 Serhiy Storchaka 在 gh-81548 [https://github.com/python/cpython/issues/81548] 中贡献。)现在从
int()
至__trunc__()
的委托已被弃用。 当type(a)
实现了__trunc__()
但未实现__int__()
或__index__()
时调用int(a)
现在将引发DeprecationWarning
。 (由 Zackery Spytz 在 bpo-44977 [https://bugs.python.org/issue?@action=redirect&bpo=44977] 中贡献。)
模块
- PEP 594 [https://peps.python.org/pep-0594/] 使得以下模块被弃用并将在 Python 3.13 中被移除:
aifc
chunk
msilib
pipes
telnetlib
audioop
crypt
nis
sndhdr
uu
cgi
imghdr
nntplib
spwd
xdrlib
cgitb
mailcap
ossaudiodev
sunau
(由 Brett Cannon 在 bpo-47061 [https://bugs.python.org/issue?@action=redirect&bpo=47061] 以及 Victor Stinner 在 gh-68966 [https://github.com/python/cpython/issues/68966] 中贡献。)
至少从 Python 3.6 起
asynchat
,asyncore
和smtpd
模块已被弃用。 它们的文档和弃用警告现在已更新为提示它们将在 Python 3.12 中被移除。 (由 Hugo van Kemenade 在 bpo-47022 [https://bugs.python.org/issue?@action=redirect&bpo=47022] 中贡献。)现在
lib2to3
包和2to3
工具已被弃用并可能无法解析 Python 3.10 或更新的版本。 请参阅引入新的 PEG 解析器的 PEP 617 [https://peps.python.org/pep-0617/] 了解详情。 (由 Victor Stinner 在 bpo-40360 [https://bugs.python.org/issue?@action=redirect&bpo=40360] 中贡献。)未写入文档的模块
sre_compile
,sre_constants
和sre_parse
现已被弃用。 (由 Serhiy Storchaka 在 bpo-47152 [https://bugs.python.org/issue?@action=redirect&bpo=47152] 中贡献。)
标准库
configparser
的下列部分自 Python 3.2 起已被弃用。 现在它们的弃用警告已更新为提示它们将在 Python 3.12 中被移除:configparser.SafeConfigParser
类configparser.ParsingError.filename
特征属性configparser.RawConfigParser.readfp()
方法
(由 Hugo van Kemenade 在 bpo-45173 [https://bugs.python.org/issue?@action=redirect&bpo=45173] 中贡献。)
configparser.LegacyInterpolation
自 Python 3.2 起已在文档字符串中被弃用,并未在configparser
文档中列出。 现在它将发出DeprecationWarning
并将在 Python 3.13 中被移除。 请改用configparser.BasicInterpolation
或configparser.ExtendedInterpolation
。 (由 Hugo van Kemenade 在 bpo-46607 [https://bugs.python.org/issue?@action=redirect&bpo=46607] 中贡献。)较旧的
importlib.resources
函数集合已被弃用而改用在 Python 3.9 中添加的替代物并将在未来的 Python 版本中被移除,因为它们不支持位于 package 子目录下的资源:importlib.resources.contents()
importlib.resources.is_resource()
importlib.resources.open_binary()
importlib.resources.open_text()
importlib.resources.read_binary()
importlib.resources.read_text()
importlib.resources.path()
locale.getdefaultlocale()
函数已被弃用并将在 Python 3.15 中移除。 请改用locale.setlocale()
,locale.getpreferredencoding(False)
和locale.getlocale()
函数。 (由 Victor Stinner 在 gh-90817 [https://github.com/python/cpython/issues/90817] 中贡献。)locale.resetlocale()
函数已被弃用并将在 Python 3.13 中移除。 请改用locale.setlocale(locale.LC_ALL, "")
。 (由 Victor Stinner 在 gh-90817 [https://github.com/python/cpython/issues/90817] 中贡献。)现在对于 正则表达式 中的数字分组引用和分组名称将应用更严格的规则。 现在只有 ASCII 数字序列会被接受作为数字引用,而
bytes
模式和替换字符串中的分组名称只能包含 ASCII 字母、数字和下划线。 目前对于违反这些规则的语法将会引发弃用警告。 (由 Serhiy Storchaka 在 gh-91760 [https://github.com/python/cpython/issues/91760] 中贡献。)在
re
模块中,re.template()
函数和相应的re.TEMPLATE
和re.T
旗标已被弃用,因为它们未被写入文档并缺少明显的目的。 它们将在 Python 3.13 中移除。 (由 Serhiy Storchaka 和 Miro Hrončok 在 gh-92728 [https://github.com/python/cpython/issues/92728] 由贡献。)turtle.settiltangle()
自 Python 3.1 起已被弃用;现在它会发出弃用警告并将在 Python 3.13 中移除。 请改用turtle.tiltangle()
(该函数在此前被错误地标记为已弃用,现在它的文档字符串已被修正)。 (由 Hugo van Kemenade 在 bpo-45837 [https://bugs.python.org/issue?@action=redirect&bpo=45837] 中贡献。)typing.Text
,它的存在只是为了在 Python 2 和 Python 3 代码之间提供兼容性支持,现在已被弃用。 目前尚无移除它的计划,但推荐用户在任何可能的地方改用str
。 (由 Alex Waygood 在 gh-92332 [https://github.com/python/cpython/issues/92332] 中贡献。)用于构造
typing.TypedDict
类型的关键字参数语法现在已被弃用。 将在 Python 3.13 中移除对它的支持。 (由 Jingchen Ye 在 gh-90224 [https://github.com/python/cpython/issues/90224] 中贡献。)webbrowser.MacOSX
已被弃用并将在 Python 3.13 中移除。 它未经测试,未写入文档,也未被webbrowser
本身所使用。 (由 Donghee Na 在 bpo-42255 [https://bugs.python.org/issue?@action=redirect&bpo=42255] 中贡献。)从
TestCase
和IsolatedAsyncioTestCase
测试方法返回一个值(默认的None
以外的值)的行为现在已被弃用。已弃用下列未正式写入文档的
unittest
函数,计划在 Python 3.13 中移除:unittest.findTestCases()
unittest.makeSuite()
unittest.getTestCaseNames()
请改用 TestLoader
方法:
(由 Erlend E. Aasland 在 bpo-5846 [https://bugs.python.org/issue?@action=redirect&bpo=5846] 中贡献。)
unittest.TestProgram.usageExit()
被标记为已弃用,将在 3.13 中被移除。 (由 Carlos Damázio 在 gh-67048 [https://github.com/python/cpython/issues/67048] 中贡献。)
计划在 Python 3.12 中移除
以下 Python API 已在之前的 Python 发布版中弃用,并将在 Python 3.12 中移除。
C API 的移除计划将 单独列出。
asynchat
模块asyncore
模块imp
模块typing.io
命名空间typing.re
命名空间cgi.log()
importlib.find_loader()
importlib.abc.Loader.module_repr()
importlib.abc.MetaPathFinder.find_module()
importlib.abc.PathEntryFinder.find_loader()
importlib.abc.PathEntryFinder.find_module()
importlib.machinery.BuiltinImporter.find_module()
importlib.machinery.BuiltinLoader.module_repr()
importlib.machinery.FileFinder.find_loader()
importlib.machinery.FileFinder.find_module()
importlib.machinery.FrozenImporter.find_module()
importlib.machinery.FrozenLoader.module_repr()
importlib.machinery.PathFinder.find_module()
importlib.machinery.WindowsRegistryFinder.find_module()
importlib.util.module_for_loader()
importlib.util.set_loader_wrapper()
importlib.util.set_package_wrapper()
pkgutil.ImpImporter
pkgutil.ImpLoader
pathlib.Path.link_to()
sqlite3.enable_shared_cache()
sqlite3.OptimizedUnicode()
PYTHONTHREADDEBUG
环境变量The following deprecated aliases in
unittest
中的下列已弃用别名:
已弃用的别名
方法名
弃用于
failUnless
3.1
failIf
3.1
failUnlessEqual
3.1
failIfEqual
3.1
failUnlessAlmostEqual
3.1
failIfAlmostEqual
3.1
failUnlessRaises
3.1
assert_
3.2
assertEquals
3.2
assertNotEquals
3.2
assertAlmostEquals
3.2
assertNotAlmostEquals
3.2
assertRegexpMatches
3.2
assertRaisesRegexp
3.2
assertNotRegexpMatches
3.5
移除
本小节列出了已在 Python 3.11 中移除的 Python API。
已移除的 C API 将 单独列出。
移除了允许旧式基于生成器的协程兼容
async
/await
代码的@asyncio.coroutine()
decorator。 该函数自 Python 3.8 起已被弃用并且原定在 Python 3.10 中移除。 请改用async def
。 (由 Illia Volochii 在 bpo-43216 [https://bugs.python.org/issue?@action=redirect&bpo=43216] 中贡献。)移除了用于在调试模式下包装旧式基于生成器的协程对象的
asyncio.coroutines.CoroWrapper
。 (由 Illia Volochii 在 bpo-43216 [https://bugs.python.org/issue?@action=redirect&bpo=43216] 中贡献。)出于显著的安全性考量,自 Python 3.9 起已被禁用的
asyncio.loop.create_datagram_endpoint()
的 reuse_address 形参现在已彻底移除。 这是因为在 UDP 中套接字选项SO_REUSEADDR
的行为。 (由 Hugo van Kemenade 在 bpo-45129 [https://bugs.python.org/issue?@action=redirect&bpo=45129] 中贡献。)移除了自 Python 3.9 起已弃用的
binhex
模块。 并移除了相关联的同样已弃用的binascii
函数:binascii.a2b_hqx()
binascii.b2a_hqx()
binascii.rlecode_hqx()
binascii.rldecode_hqx()
binascii.crc_hqx()
函数仍然可用。
(由 Victor Stinner 在 bpo-45085 [https://bugs.python.org/issue?@action=redirect&bpo=45085] 中贡献。)
移除了自 Python 3.9 起已弃用的
distutils
bdist_msi
命令。 请改用bdist_wheel
(wheel 包)。 (由 Hugo van Kemenade 在 bpo-45124 [https://bugs.python.org/issue?@action=redirect&bpo=45124] 中贡献。)移除了自 Python 3.9 起已弃用的
xml.dom.pulldom.DOMEventStream
,wsgiref.util.FileWrapper
和fileinput.FileInput
的__getitem__()
方法。 (由 Hugo van Kemenade 在 bpo-45132 [https://bugs.python.org/issue?@action=redirect&bpo=45132] 中贡献。)移除了已弃用的
gettext
函数lgettext()
,ldgettext()
,lngettext()
和ldngettext()
。 并移除了bind_textdomain_codeset()
函数、NullTranslations.output_charset()
和NullTranslations.set_output_charset()
方法,以及translation()
和install()
的 codeset 形参 ,因为它们仅被用于l*gettext()
函数。 (由 Donghee Na 和 Serhiy Storchaka 在 bpo-44235 [https://bugs.python.org/issue?@action=redirect&bpo=44235] 中贡献。)已从
inspect
模块中移除:getargspec()
函数自 Python 3.0 起已被弃用;请改用inspect.signature()
或inspect.getfullargspec()
。formatargspec()
函数自 Python 3.5 起已被弃用;请改用inspect.signature()
函数或直接使用inspect.Signature
对象。未写入文档的
Signature.from_builtin()
和Signature.from_function()
方法自 Python 3.5 起已被弃用;请改用Signature.from_callable()
方法。
(由 Hugo van Kemenade 在 bpo-45320 [https://bugs.python.org/issue?@action=redirect&bpo=45320] 中贡献。)
从
pathlib.PurePath
中移除了__class_getitem__()
方法,因为它从未被使用而是在之前版本中误添加的。 (由 Nikita Sobolev 在 bpo-46483 [https://bugs.python.org/issue?@action=redirect&bpo=46483] 中贡献。)移除了
smtpd
模块中的MailmanProxy
类,因为它在没有外部mailman
包时是无法使用的。 (由 Donghee Na 在 bpo-35800 [https://bugs.python.org/issue?@action=redirect&bpo=35800] 中贡献。)移除了
_tkinter.TkappType
中已被弃用的split()
方法。 (由 Erlend E. Aasland 在 bpo-38371 [https://bugs.python.org/issue?@action=redirect&bpo=38371] 中贡献。)从
unittest
发现中移除了命名空间包支持。 它在 Python 3.4 中引入但自 Python 3.7 起已不可用。 (由 Inada Naoki 在 bpo-23882 [https://bugs.python.org/issue?@action=redirect&bpo=23882] 中贡献。)移除了未写入文档的私有
float.__set_format__()
方法,之前在 Python 3.7 中名为float.__setformat__()
。 其文档字符串已写明:“你应该不需要使用此函数。 它的存在主要是用于 Python 的测试套件。” (由 Victor Stinner 在 bpo-46852 [https://bugs.python.org/issue?@action=redirect&bpo=46852] 中贡献。)--experimental-isolated-subinterpreters
配置旗标(和相应的EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
宏)已被移除。Pynche [https://pypi.org/project/Pynche/] —- The Pythonically Natural Color and Hue Editor —- 已被移出
Tools/scripts
并且脱离Python 源代码树转为 独立开发 [https://gitlab.com/warsaw/pynche/-/tree/main]。
移植到 Python 3.11
本节列出了先前描述的更改以及 Python API 中可能需要修改你的 Python 代码的其他错误修正。
针对 C API 的移植说明将 单独列出。
open()
,io.open()
,codecs.open()
和fileinput.FileInput
的文件模式中不再接受'U'
("通用换行符")。 在 Python 3 中,"通用换行符" 模式会在文件以文本模式打开时默认被使用,而'U'
旗标自 Python 3.3 起已被弃用。 这些函数的 newline 形参 将控制如何使用通用换行符。 (由 Victor Stinner 在 bpo-37330 [https://bugs.python.org/issue?@action=redirect&bpo=37330] 中贡献。)现在
ast.AST
节点位置在提供给compile()
和其他相关函数时会进行验证。 如果检测到无效位置, 将会引发ValueError
。 (由 Pablo Galindo 在 gh-93351 [https://github.com/python/cpython/issues/93351] 中提供。)继在 Python 3.8 中弃用后,已禁止向
asyncio.loop.set_default_executor()
传入非concurrent.futures.ThreadPoolExecutor
执行器。(由 Illia Volochii 在 bpo-43234 [https://bugs.python.org/issue?@action=redirect&bpo=43234] 中贡献。)calendar
: 在未指定语言区域的情况下,calendar.LocaleTextCalendar
和calendar.LocaleHTMLCalendar
类现在会使用locale.getlocale()
,而不是使用locale.getdefaultlocale()
。 (由 Victor Stinner 在 bpo-46659 [https://bugs.python.org/issue?@action=redirect&bpo=46659] 中贡献。)现在
pdb
模块会使用'UTF-8'
编码来读取.pdbrc
配置文件。 (由 Srinivas Reddy Thatiparthy (శ్రీనివాస్ రెడ్డి తాటిపర్తి) 在 bpo-41137 [https://bugs.python.org/issue?@action=redirect&bpo=41137] 中贡献。)random.sample()
的 population 形参必须是一个序列,不再支持将set
自动转换为list
。 此外,如果样本大小大于总体大小,将会引发ValueError
。 (由 Raymond Hettinger 在 bpo-40465 [https://bugs.python.org/issue?@action=redirect&bpo=40465] 中贡献。)移除了
random.shuffle()
的 random 可选形参。 在之前版本中重排操作是使用任意随机函数;现在,将始终使用random.random()
(之前的默认值)。在
re
正则表达式语法 中,全局内联旗标 (例如(?i)
) 现在只能在正则表达式的开头使用。 自 Python 3.6 起在别处使用这些旗标的做法已被弃用。 (由 Serhiy Storchaka 在 bpo-47066 [https://bugs.python.org/issue?@action=redirect&bpo=47066] 中贡献)。在
re
模块中,修复了几个长期存在的错误,在极少数情况下,这些错误可能会导致捕获分组得到错误的结果。 因此,这可能会改变这些情况下的捕获输出。 (由 Ma Lin 在 bpo-35859 [https://bugs.python.org/issue?@action=redirect&bpo=35859] 中贡献。)
构建变化
CPython 现已具有 PEP 11 [https://peps.python.org/pep-0011/] Tier 3 support [https://peps.python.org/pep-0011/#tier-3] 以便交叉编译至 WebAssembly [https://webassembly.org/] 平台 Emscripten [https://emscripten.org/] (
wasm32-unknown-emscripten
即浏览器版 Python) 和 WebAssembly System Interface (WASI) [https://wasi.dev/] (wasm32-unknown-wasi
)。 此计划的灵感来自前人的工作如 Pyodide [https://pyodide.org/]。 这些平台提供了 POSIX API 的有限子集;与网络、进程、线程、信号、mmap 和用户/组相关的 Python 标准库特性和模块将不可用或无法正常工作。 (Emscripten 由 Christian Heimes 和 Ethan Smith 在 gh-84461 [https://github.com/python/cpython/issues/84461] 中贡献,WASI 由 Christian Heimes 在 gh-90473 [https://github.com/python/cpython/issues/90473] 中贡献;平台的推进在 gh-95085 [https://github.com/python/cpython/issues/95085] 中追踪。)构建 CPython 现在需要:
C11 [https://en.cppreference.com/w/c/11] 编译器和标准库。 可选的 C11 特性#Optionalfeatures) [https://en.wikipedia.org/wiki/C11(C_standard_revision)#Optional_features] 不是必须的。 (由 Victor Stinner 在 bpo-46656 [https://bugs.python.org/issue?@action=redirect&bpo=46656], bpo-45440 [https://bugs.python.org/issue?@action=redirect&bpo=45440] 和 bpo-46640 [https://bugs.python.org/issue?@action=redirect&bpo=46640] 中贡献。)
对 IEEE 754 [https://en.wikipedia.org/wiki/IEEE_754] 浮点数的支持。 (由 Victor Stinner 在 bpo-46917 [https://bugs.python.org/issue?@action=redirect&bpo=46917] 中贡献。)
Py_NO_NAN
宏已被移除。 由于 CPython 现在要求 IEEE 754 浮点数,NaN 值将始终可用。 (由 Victor Stinner 在 bpo-46656 [https://bugs.python.org/issue?@action=redirect&bpo=46656] 中贡献。)tkinter
包现在需要 Tcl/Tk [https://www.tcl.tk] 8.5.12 或更新的版本。 (由 Serhiy Storchaka 在 bpo-46996 [https://bugs.python.org/issue?@action=redirect&bpo=46996] 中贡献。)大多数标准库扩展模块的构建依赖、编译器旗标和链接器旗标现在将由 configure 来检测。 libffi, libnsl, libsqlite3, zlib, bzip2, liblzma, libcrypt, Tcl/Tk 和 uuid 旗标将由 pkg-config [https://www.freedesktop.org/wiki/Software/pkg-config/] (如果可用) 来检测。
tkinter
现在需要由 pkg-config 命令来检测 Tcl/Tk [https://www.tcl.tk] 标头和库的开发设置。 (由 Christian Heimes 和 Erlend Egeberg Aasland 在 bpo-45847 [https://bugs.python.org/issue?@action=redirect&bpo=45847], bpo-45747 [https://bugs.python.org/issue?@action=redirect&bpo=45747] 和 bpo-45763 [https://bugs.python.org/issue?@action=redirect&bpo=45763] 中贡献。)libpython 不再与 libcrypt 链接。 (由 Mike Gilbert 在 bpo-45433 [https://bugs.python.org/issue?@action=redirect&bpo=45433] 中贡献。)
现在 CPython 可以通过向
--with-lto
传入thin
,即--with-lto=thin
在编译时启用 ThinLTO [https://clang.llvm.org/docs/ThinLTO.html] 选项。 (由 Donghee Na 和 Brett Holman 在 bpo-44340 [https://bugs.python.org/issue?@action=redirect&bpo=44340] 中贡献。)现在可以禁用对象结构体的自由列表。 新的 configure 选项
--without-freelists
可用于禁用除空元组单例之外的所有自由列表。 (由 Christian Heimes 在 bpo-45522 [https://bugs.python.org/issue?@action=redirect&bpo=45522] 中贡献。)Modules/Setup
和Modules/makesetup
已获得改进并进行绑定。 扩展模块现在可以通过makesetup
来构建。 除部分测试模块外所有模块都可以静态链接到主二进制文件或库中。 (由 Brett Cannon 和 Christian Heimes 在 bpo-45548 [https://bugs.python.org/issue?@action=redirect&bpo=45548], bpo-45570 [https://bugs.python.org/issue?@action=redirect&bpo=45570], bpo-45571 [https://bugs.python.org/issue?@action=redirect&bpo=45571] 和 bpo-43974 [https://bugs.python.org/issue?@action=redirect&bpo=43974] 中贡献。)
备注
使用环境变量 TCLTK_CFLAGS
和 TCLTK_LIBS
来手动指定 Tcl/Tk 头文件和库的位置。 configure 选项 --with-tcltk-includes
和 --with-tcltk-libs
已被移除。
在 RHEL 7 和 CentOS 7 上开发包将不提供 tcl.pc
和 tk.pc
;请使用 TCLTK_LIBS="-ltk8.5 -ltkstub8.5 -ltcl8.5"
。 Misc/rhel7
目录包含 .pc
文件以及如何使用 RHEL 7 和 CentOS 7 的 Tcl/Tk 和 OpenSSL 构建 Python 的说明。
- CPython 现在将默认使用 30 比特位的数字来实现 Python
int
。 之前版本中,在SIZEOF_VOID_P >= 8
的平台上默认使用 30 比特位数字,否则使用 15 位数字。 仍然有可能通过配置脚本的--enable-big-digits
选项或PC/pyconfig.h
中的PYLONG_BITS_IN_DIGIT
变量(适用于 Windows)显式地要求使用 15 比特位数字,但该选项可能会在未来某个时候被移除。 (由 Mark Dickinson 在 bpo-45569 [https://bugs.python.org/issue?@action=redirect&bpo=45569] 中贡献。)
C API 的变化
新的特性
新增了
PyType_GetName()
函数用来获取类型的简短名称。 (由 Hai Shi 在 bpo-42035 [https://bugs.python.org/issue?@action=redirect&bpo=42035] 中贡献。)新增了
PyType_GetQualName()
函数用来获取类型的限定名称。 (由 Hai Shi 在 bpo-42035 [https://bugs.python.org/issue?@action=redirect&bpo=42035] 中贡献。)在受限的 C API 中新增了
PyThreadState_EnterTracing()
和PyThreadState_LeaveTracing()
函数用来挂起和恢复追踪和性能分析。 (由 Victor Stinner 在 bpo-43760 [https://bugs.python.org/issue?@action=redirect&bpo=43760] 中贡献。)增加了
Py_Version
常量,其中的值与PY_VERSION_HEX
相同。 (由 Gabriele N. Tornetta 在 bpo-43931 [https://bugs.python.org/issue?@action=redirect&bpo=43931] 中贡献。)Py_buffer
及其 API 现在是受限 API 和稳定 ABI 的组成部分:bf_getbuffer
和bf_releasebuffer
类型槽位
(由 Christian Heimes 在 bpo-45459 [https://bugs.python.org/issue?@action=redirect&bpo=45459] 中贡献。)
增加了
PyType_GetModuleByDef()
函数,用于在无法直接获取信息的情况下 (通过PyCMethod
) 获取方法定义所在的模块。 (由 Petr Viktorin 在 bpo-46613 [https://bugs.python.org/issue?@action=redirect&bpo=46613] 中贡献。)添加了用于打包和解包 C double (序列化和反序列化) 的新函数:
PyFloat_Pack2()
,PyFloat_Pack4()
,PyFloat_Pack8()
,PyFloat_Unpack2()
,PyFloat_Unpack4()
和PyFloat_Unpack8()
。 (由 Victor Stinner 在 bpo-46906 [https://bugs.python.org/issue?@action=redirect&bpo=46906] 中贡献。)添加了用于获取帧对象属性的新函数:
PyFrame_GetBuiltins()
,PyFrame_GetGenerator()
,PyFrame_GetGlobals()
,PyFrame_GetLasti()
。新增了两个用于获取和设置活动异常实例的函数:
PyErr_GetHandledException()
和PyErr_SetHandledException()
。 这两个函数是PyErr_SetExcInfo()
和PyErr_GetExcInfo()
的替代品,后者使用传统的 3 元组表示异常。 (由 Irit Katriel 在 bpo-46343 [https://bugs.python.org/issue?@action=redirect&bpo=46343] 中贡献。)添加了
PyConfig.safe_path
成员。 (由 Victor Stinner 在 gh-57684 [https://github.com/python/cpython/issues/57684] 中贡献。).)
移植到 Python 3.11
部分宏已被转换为静态内联函数以避免 宏陷阱 [https://gcc.gnu.org/onlinedocs/cpp/Macro-Pitfalls.html]。 这项改变对用户来说应该是基本无感的,因为替代函数会将其参数强制转换为预期的类型以避免静态类型检查导致的编译器警告。 但是,当受限 C API 被设为 >=3.11 时,将不会执行这些强制转换,调用方将需要自行将参数强制转换为其预期的类型。 请参阅 PEP 670 [https://peps.python.org/pep-0670/] 了解详情。 (由 Victor Stinner 和 Erlend E. Aasland 在 gh-89653 [https://github.com/python/cpython/issues/89653] 中贡献。)
PyErr_SetExcInfo()
不再使用type
和traceback
参数,解释器现在将从异常实例( 即value
参数)中获取这些值。 该函数仍会偷取对所有三个参数的引用。 (由 Irit Katriel 在 bpo-45711 [https://bugs.python.org/issue?@action=redirect&bpo=45711] 中贡献。)PyErr_GetExcInfo()
现在将从异常实例(即value
字段)获取结果的type
和traceback
字段。 (由 Irit Katriel 在 bpo-45711 [https://bugs.python.org/issue?@action=redirect&bpo=45711] 中贡献。)_frozen
新增了is_package
字段用来指明冻结模块是否为包。 之前,是将size
字段设置负值作为指示符。 现在size
将只使用非负值。 (由 Kumar Aditya 在 bpo-46608 [https://bugs.python.org/issue?@action=redirect&bpo=46608] 中贡献。)现在
_PyFrameEvalFunction()
接受_PyInterpreterFrame*
作为其第二个形参,而不是PyFrameObject*
。 请参阅 PEP 523 [https://peps.python.org/pep-0523/] 了解如何使用此函数指针类型的更多细节。现在
PyCode_New()
和PyCode_NewWithPosOnlyArgs()
接受一个额外的exception_table
参数。 如有可能,应当避免使用这些函数。 获取自定义的代码对象:使用编译器创建一个代码对象,然后使用replace
方法得到修改后的版本。PyCodeObject
不再具有co_code
,co_varnames
,co_cellvars
和co_freevars
字段。 请分别改用PyCode_GetCode()
,PyCode_GetVarnames()
,PyCode_GetCellvars()
和PyCode_GetFreevars()
通过 C API 来访问它们。 (由 Brandt Bucher 在 bpo-46841 [https://bugs.python.org/issue?@action=redirect&bpo=46841] 以及 Ken Jin 在 gh-92154 [https://github.com/python/cpython/issues/92154] 和 gh-94936 [https://github.com/python/cpython/issues/94936] 中贡献。)旧的垃圾桶宏 (
Py_TRASHCAN_SAFE_BEGIN
/Py_TRASHCAN_SAFE_END
) 现在已被弃用。 它们应该由新的宏Py_TRASHCAN_BEGIN
和Py_TRASHCAN_END
代替。
带有旧版宏的 tp_dealloc 函数,例如:
- static void
- mytype_dealloc(mytype *p)
- {
- PyObject_GC_UnTrack(p);
- Py_TRASHCAN_SAFE_BEGIN(p);
- ...
- Py_TRASHCAN_SAFE_END
- }
应当按照以下方式迁移到新版宏:
- static void
- mytype_dealloc(mytype *p)
- {
- PyObject_GC_UnTrack(p);
- Py_TRASHCAN_BEGIN(p, mytype_dealloc)
- ...
- Py_TRASHCAN_END
- }
请注意 Py_TRASHCAN_BEGIN
的第二个参数应该是它所属的取消分配函数。
要在同一代码库中支持旧版本的 Python,可以定义以下的宏并在整个代码中使用它们 (版权声明:这些宏是从 mypy
代码库中拷贝的):
- #if PY_VERSION_HEX >= 0x03080000
- # define CPy_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_BEGIN(op, dealloc)
- # define CPy_TRASHCAN_END(op) Py_TRASHCAN_END
- #else
- # define CPy_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_SAFE_BEGIN(op)
- # define CPy_TRASHCAN_END(op) Py_TRASHCAN_SAFE_END(op)
- #endif
现在如果一个类型定义了
Py_TPFLAGS_HAVE_GC
旗标但没有遍历函数 (PyTypeObject.tp_traverse
) 则PyType_Ready()
函数将引发一个错误。 (由 Victor Stinner 在 bpo-44263 [https://bugs.python.org/issue?@action=redirect&bpo=44263] 中贡献。)带有
Py_TPFLAGS_IMMUTABLETYPE
旗标的堆类型现在可以继承 PEP 590 [https://peps.python.org/pep-0590/] vectorcall 协议。 在之前版本中,这只适用于 静态类型。(由 Erlend E. Aasland 在 bpo-43908 [https://bugs.python.org/issue?@action=redirect&bpo=43908] 中贡献。)由于
Py_TYPE()
已改为内联静态函数,因此Py_TYPE(obj) = new_type
必须换成Py_SET_TYPE(obj, new_type)
: 参见Py_SET_TYPE()
函数(自 Python 3.9 起可用)。 为保持向下兼容,可以使用这个宏:
- #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
- static inline void PySET_TYPE(PyObject *ob, PyTypeObject *type)
- { ob->ob_type = type; }
- #define Py_SET_TYPE(ob, type) PySET_TYPE((PyObject*)(ob), type)
- #endif
(由 Victor Stinner 在 bpo-39573 [https://bugs.python.org/issue?@action=redirect&bpo=39573] 中贡献。)
- 由于
Py_SIZE()
已改为内联静态函数,因此Py_SIZE(obj) = new_size
必须换成Py_SET_SIZE(obj, new_size)
: 参见Py_SET_SIZE()
函数(自 Python 3.9 起可用)。 为保持向下兼容,可以使用这个宏:
- #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE)
- static inline void PySET_SIZE(PyVarObject *ob, Py_ssize_t size)
- { ob->ob_size = size; }
- #define Py_SET_SIZE(ob, size) PySET_SIZE((PyVarObject*)(ob), size)
- #endif
(由 Victor Stinner 在 bpo-39573 [https://bugs.python.org/issue?@action=redirect&bpo=39573] 中贡献。)
在
Py_LIMITED_API
宏被设为0x030b0000
(Python 3.11) 或更高版本时,
将不再包含头文件
,
,
和
。 C 扩展应在#include
之后显式地包括头文件。 (由 Victor Stinner 在 bpo-45434 [https://bugs.python.org/issue?@action=redirect&bpo=45434] 中贡献。)非受限 API 文件
cellobject.h
,classobject.h
,code.h
,context.h
,funcobject.h
,genobject.h
和longintrepr.h
已被移至Include/cpython
目录。 此外,还移除了eval.h
头文件。 这些文件不能被直接包括,因为它们已经被包括在Python.h
中了:参见 包括文件。如果它们已被直接包括,请考虑改为包括Python.h
。 (由 Victor Stinner 在 bpo-35134 [https://bugs.python.org/issue?@action=redirect&bpo=35134] 中贡献。)PyUnicode_CHECK_INTERNED()
宏已被排除在受限 C API 之外。 它从未在那里被使用,因为它使用了受限 C API 中不可用的内部结构体。 (由 Victor Stinner 在 bpo-46007 [https://bugs.python.org/issue?@action=redirect&bpo=46007] 中贡献。)以下帧函数和类型现在可通过
#include
直接使用,不再需要添加#include
:
(由 Victor Stinner 在 gh-93937 [https://github.com/python/cpython/issues/93937] 中贡献。)
PyFrameObject
结构体成员已从公有 C API 中被移除。
虽然文档指出 PyFrameObject
字段可能随时更改,但这些字段长期以来一直保持稳定,并在多个流行的扩展中使用。
在 Python 3.11 中,为了优化性能,对帧结构进行了重组。 一些字段被完全删除,因为它们属于旧实现的细节。
PyFrameObject
字段:
f_back
: 使用PyFrame_GetBack()
。f_blockstack
: 已移除。f_builtins
: 使用PyFrame_GetBuiltins()
。f_code
: 使用PyFrame_GetCode()
。f_gen
: 使用PyFrame_GetGenerator()
。f_globals
: 使用PyFrame_GetGlobals()
。f_iblock
: 已移除。f_lasti
: 使用PyFrame_GetLasti()
。 使用f_lasti
并带有PyCode_Addr2Line()
的代码应当改用PyFrame_GetLineNumber()
;它可能会更快。f_lineno
: 使用PyFrame_GetLineNumber()
f_locals
: 使用PyFrame_GetLocals()
。f_stackdepth
: 已移除。f_state
: 无公共 API (重命名为f_frame.f_state
)。f_trace
: 无公共 API。f_trace_lines
: 使用PyObject_GetAttrString((PyObject*)frame, "f_trace_lines")
。f_trace_opcodes
: 使用PyObject_GetAttrString((PyObject*)frame, "f_trace_opcodes")
。f_localsplus
: 无公共 API (重命名为f_frame.localsplus
)。f_valuestack
: 已移除。
现在 Python 帧对象是惰性地创建的。 一个附带影响是 f_back
成员不可被直接访问,因为现在它的值也是惰性地计算的。 必须改为调用 PyFrame_GetBack()
函数。
直接访问 f_locals
的调试器 必须 改为调用 PyFrame_GetLocals()
。 它们不再需要调用 PyFrame_FastToLocalsWithError()
或 PyFrame_LocalsToFast()
,实际上它们不应调用这些函数。 现在帧所需要的更新将由虚拟机来管理。
在 Python 3.8 及更旧版本上定义 PyFrame_GetCode()
的代码:
- #if PY_VERSION_HEX < 0x030900B1
- static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame)
- {
- Py_INCREF(frame->f_code);
- return frame->f_code;
- }
- #endif
在 Python 3.8 及更旧版本上定义 PyFrame_GetBack()
的代码:
- #if PY_VERSION_HEX < 0x030900B1
- static inline PyFrameObject* PyFrame_GetBack(PyFrameObject *frame)
- {
- Py_XINCREF(frame->f_back);
- return frame->f_back;
- }
- #endif
或者使用 pythoncapi_compat 项目 [https://github.com/python/pythoncapi-compat] 在更旧版本的 Python 上获取这些函数。
PyThreadState
结构体成员的变化:frame
: 已被移除,请使用PyThreadState_GetFrame()
(由 bpo-40429 [https://bugs.python.org/issue?@action=redirect&bpo=40429] 添加到 Python 3.9 的函数)。 警告:该函数返回一个 strong reference,需要调用Py_XDECREF()
。tracing
: 已被更改,请使用PyThreadState_EnterTracing()
和PyThreadState_LeaveTracing()
(由:issue:43760 添加到 Python 3.11 的函数)。recursion_depth
: 已被移除,请使用(tstate->recursion_limit - tstate->recursion_remaining)
代替。stackcheck_counter
:已移除。
在 Python 3.8 或更旧版本中定义 PyThreadState_GetFrame()
的代码:
- #if PY_VERSION_HEX < 0x030900B1
- static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
- {
- Py_XINCREF(tstate->frame);
- return tstate->frame;
- }
- #endif
在 Python 3.10 或更旧版本中定义 PyThreadState_EnterTracing()
和 PyThreadState_LeaveTracing()
的代码:
- #if PY_VERSION_HEX < 0x030B00A2
- static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
- {
- tstate->tracing++;
- #if PY_VERSION_HEX >= 0x030A00A1
- tstate->cframe->use_tracing = 0;
- #else
- tstate->use_tracing = 0;
- #endif
- }
- static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
- {
- int use_tracing = (tstate->c_tracefunc != NULL || tstate->c_profilefunc != NULL);
- tstate->tracing--;
- #if PY_VERSION_HEX >= 0x030A00A1
- tstate->cframe->use_tracing = use_tracing;
- #else
- tstate->use_tracing = use_tracing;
- #endif
- }
- #endif
或者使用 pythoncapi-compat 项目 [https://github.com/python/pythoncapi-compat] 在旧版的 Python 函数上获取这些函数。
推荐发行方使用优化的 Blake2 库 libb2 [https://www.blake2.net/] 来构建 Python。
现在初始化时
PyConfig.module_search_paths_set
字段必须设为 1 以使用PyConfig.module_search_paths
来初始化sys.path
。 否则,初始化将重新计算路径并替换任何加入到module_search_paths
的值。PyConfig_Read()
将不会再计算初始搜索路径,并且不会将任何值填充到PyConfig.module_search_paths
。 要计算默认路径再修改它们,请结束初始化并使用PySys_GetObject()
来将sys.path
提取为一个 Python 列表对象并直接修改它。
弃用
弃用以下配置 Python 初始化的函数:
PySys_AddWarnOptionUnicode()
PySys_AddWarnOption()
PySys_AddXOption()
PySys_HasWarnOptions()
PySys_SetArgvEx()
PySys_SetArgv()
PySys_SetPath()
Py_SetPath()
Py_SetProgramName()
Py_SetPythonHome()
Py_SetStandardStreamEncoding()
PySetProgramFullPath()
改用新的 Python 初始化配置 的 PyConfig
API ( PEP 587 [https://peps.python.org/pep-0587/])。 (由 Victor Stinner 在 gh-88279 [https://github.com/python/cpython/issues/88279] 中贡献。)
- 弃用
PyBytesObject
的ob_shash
成员。 改用PyObject_Hash()
。 (由 Inada Naoki 在 bpo-46864 [https://bugs.python.org/issue?@action=redirect&bpo=46864] 中贡献。).)
计划在 Python 3.12 中移除
以下 C API 在早期 Python 发行版中已经弃用,将在 Python 3.12 中移除。
PyUnicode_AS_DATA()
PyUnicode_AS_UNICODE()
PyUnicode_AsUnicodeAndSize()
PyUnicode_AsUnicode()
PyUnicode_FromUnicode()
PyUnicode_GET_DATA_SIZE()
PyUnicode_GET_SIZE()
PyUnicode_GetSize()
PyUnicode_IS_COMPACT()
PyUnicode_IS_READY()
PyUnicode_WSTR_LENGTH()
PyUnicodeAsUnicode()
PyUnicode_WCHAR_KIND
PyUnicode_InternImmortal()
移除
PyFrame_BlockSetup()
和PyFrame_BlockPop()
已被移除。 (由 Mark Shannon 在 bpo-40222 [https://bugs.python.org/issue?@action=redirect&bpo=40222] 中贡献。)移除了下列使用
errno
变量的数学宏:Py_ADJUST_ERANGE1()
Py_ADJUST_ERANGE2()
Py_OVERFLOWED()
Py_SET_ERANGE_IF_OVERFLOW()
Py_SET_ERRNO_ON_MATH_ERROR()
(由 Victor Stinner 在 bpo-45412 [https://bugs.python.org/issue?@action=redirect&bpo=45412] 中贡献。)
移除
Py_UNICODE_COPY()
和Py_UNICODE_FILL()
宏,它们自 Python 3.3 起已被弃用。 改用PyUnicode_CopyCharacters()
或memcpy()
(wchar_t*
字符串) 和PyUnicode_Fill()
函数。 (由 Victor Stinner 在 bpo-41123 [https://bugs.python.org/issue?@action=redirect&bpo=41123] 中贡献。)移除
pystrhex.h
头文件。 它只包含私有函数。 C 扩展应当只包括主
头文件。 (由 Victor Stinner 在 bpo-45434 [https://bugs.python.org/issue?@action=redirect&bpo=45434] 中贡献。)移除了
Py_FORCE_DOUBLE()
宏,它曾经由Py_IS_INFINITY()
宏使用。(由 Victor Stinner 在 bpo-45440 [https://bugs.python.org/issue?@action=redirect&bpo=45440] 贡献。)以下项目在
Py_LIMITED_API
定义时不再可用:
这些不是 受限 API 的组成部分。
(由 Victor Stinner 在 bpo-45474 [https://bugs.python.org/issue?@action=redirect&bpo=45474] 中贡献。)
将
PyWeakref_GET_OBJECT()
排除在受限 C API 之外。 由于PyWeakReference
结构体在受限 C API 中被屏蔽因此它从未发挥作用。 (由 Victor Stinner 在 bpo-35134 [https://bugs.python.org/issue?@action=redirect&bpo=35134] 中贡献。)移除了
PyHeapType_GET_MEMBERS()
宏。它错误地暴露在公开的 C API 中,且只能由 Python 在内部使用。请使用PyTypeObject.tp_members
作为替代。(由 Victor Stinner 在 bpo-40170 [https://bugs.python.org/issue?@action=redirect&bpo=40170] 贡献。)移除了
HAVE_PY_SET_53BIT_PRECISION
宏(移动到了内部 C API)。(由 Victor Stinner 在 bpo-45412 [https://bugs.python.org/issue?@action=redirect&bpo=45412] 贡献。)
- 移除了
Py_UNICODE
编码器 API,它们从 Python 3.3 起已经弃用,很少使用,而且相对于推荐的替代品来说,效率很低。
被移除的函数有:
PyUnicode_Encode()
PyUnicode_EncodeASCII()
PyUnicode_EncodeLatin1()
PyUnicode_EncodeUTF7()
PyUnicode_EncodeUTF8()
PyUnicode_EncodeUTF16()
PyUnicode_EncodeUTF32()
PyUnicode_EncodeUnicodeEscape()
PyUnicode_EncodeRawUnicodeEscape()
PyUnicode_EncodeCharmap()
PyUnicode_TranslateCharmap()
PyUnicode_EncodeDecimal()
PyUnicode_TransformDecimalToASCII()
请参阅 PEP 624 [https://peps.python.org/pep-0624/] 了解细节以及 迁移指引 [https://peps.python.org/pep-0624/#alternative-apis]。 (由 Inada Naoki 在 bpo-44029 [https://bugs.python.org/issue?@action=redirect&bpo=44029] 中贡献。)
3.11.4 中的重要变化
tarfile
tarfile
中的提取方法和shutil.unpack_archive()
都新增了 filter 参数以允许限制可能令人意外或危险的 tar 特性,例如在目标目录之外创建文件。 相关细节参见 解压缩过滤器。 在 Python 3.12 中,不带 filter 参数的用法将显示DeprecationWarning
。 在 Python 3.14 中,默认值将切换为'data'
。 (由 Petr Viktorin 在 PEP 706 [https://peps.python.org/pep-0706/] 中贡献。)
3.11.5 中的重要变化
OpenSSL
- 来自 python.org 的 Windows 版本和 macOS 安装程序现在使用 OpenSSL 3.0。