Python 3.11 中的新功能

编辑:

Pablo Galindo Salgado

本文解释了 Python 3.11 相对于 3.10 的新功能。Python 3.11 于 2022 年 10 月 24 日发布。有关完整详细信息,请参阅 更新日志

摘要 – 发布亮点

  • Python 3.11 比 Python 3.10 快 10-60%。平均而言,我们在标准基准测试套件上测得 1.25 倍的加速。有关详细信息,请参阅 更快的 CPython

新语法功能

新的内置功能

新的标准库模块

解释器的改进

新的类型特性

重要的废弃、移除和限制

新功能

PEP 657: 追溯中更精细的错误位置

现在,在打印追溯时,解释器将指向导致错误的精确表达式,而不仅仅是行。例如

Traceback (most recent call last):
  File "distance.py", line 11, in <module>
    print(manhattan_distance(p1, p2))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "distance.py", line 6, in manhattan_distance
    return abs(point_1.x - point_2.x) + abs(point_1.y - point_2.y)
                           ^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'x'

以前的解释器版本只会指向行,使得哪个对象是 None 变得模糊不清。这些增强的错误在处理深度嵌套的 dict 对象和多个函数调用时也很有帮助

Traceback (most recent call last):
  File "query.py", line 37, in <module>
    magic_arithmetic('foo')
  File "query.py", line 18, in magic_arithmetic
    return add_counts(x) / 25
           ^^^^^^^^^^^^^
  File "query.py", line 24, in add_counts
    return 25 + query_user(user1) + query_user(user2)
                ^^^^^^^^^^^^^^^^^
  File "query.py", line 32, in query_user
    return 1 + query_count(db, response['a']['b']['c']['user'], retry=True)
                               ~~~~~~~~~~~~~~~~~~^^^^^
TypeError: 'NoneType' object is not subscriptable

以及复杂的算术表达式

Traceback (most recent call last):
  File "calculation.py", line 54, in <module>
    result = (x / y / z) * (a / b / c)
              ~~~~~~^~~
ZeroDivisionError: division by zero

此外,增强的追溯功能所使用的信息可通过通用 API 获得,该 API 可用于关联 字节码 指令 与源代码位置。此信息可以使用以下方法检索

有关更多详细信息,请参阅 PEP 657。(由 Pablo Galindo、Batuhan Taskaya 和 Ammar Askar 在 bpo-43950 中贡献。)

备注

此功能要求在 代码对象 中存储列位置,这可能会导致解释器内存使用量和编译后的 Python 文件磁盘使用量略有增加。为了避免存储额外信息并停用打印额外追溯信息,请使用 -X no_debug_ranges 命令行选项或 PYTHONNODEBUGRANGES 环境变量。

PEP 654: 异常组和 except*

PEP 654 引入了语言功能,使程序能够同时引发和处理多个不相关的异常。内置类型 ExceptionGroupBaseExceptionGroup 使得可以将异常分组并一起引发,新的 except* 语法将 except 泛化以匹配异常组的子组。

有关更多详细信息,请参阅 PEP 654

(由 Irit Katriel 在 bpo-45292 中贡献。PEP 由 Irit Katriel、Yury Selivanov 和 Guido van Rossum 编写。)

PEP 678: 异常可添加注释

add_note() 方法已添加到 BaseException。它可用于为异常添加在引发异常时不可用的上下文信息。添加的注释会出现在默认追溯中。

有关更多详细信息,请参阅 PEP 678

(由 Irit Katriel 在 bpo-45607 中贡献。PEP 由 Zac Hatfield-Dodds 编写。)

Windows py.exe 启动器改进

Python 3.11 中包含的 Python 安装管理器 副本已显著更新。它现在支持 PEP 514 中定义的公司/标签语法,使用 -V:<company>/<tag> 参数,而不是有限的 -<major>.<minor>。这允许启动 python.org 上托管的 PythonCore 之外的分发。

使用 -V: 选择器时,可以省略公司或标签,但会搜索所有安装。例如,-V:OtherPython/ 将选择为 OtherPython 注册的“最佳”标签,而 -V:3.11-V:/3.11 将选择标签为 3.11 的“最佳”分发。

使用旧的 -<major>-<major>.<minor>-<major>-<bitness>-<major>.<minor>-<bitness> 参数时,所有现有行为都应保留与过去版本相同,并且只会选择 PythonCore 的发行版。然而,-64 后缀现在意味着“非 32 位”(不一定是 x86-64),因为有多个受支持的 64 位平台。32 位运行时通过检查运行时的标签是否包含 -32 后缀来检测。自 3.5 以来,所有 Python 版本都在其 32 位构建中包含了此后缀。

其他语言更改

  • 添加了 -P 命令行选项和 PYTHONSAFEPATH 环境变量,它们会禁用在运行脚本时将脚本目录自动添加到 sys.path,或者在使用 -c-m 时将当前目录自动添加到 sys.path。这确保 import 只会查找标准库和已安装的模块,并避免无意或恶意地使用本地(通常是用户可写)目录中的模块来遮盖模块。(由 Victor Stinner 在 gh-57684 中贡献。)

  • 格式化规范迷你语言 中添加了一个 "z" 选项,它在舍入到格式精度后将负零强制转换为正零。有关更多详细信息,请参阅 PEP 682。(由 John Belmonte 在 gh-90153 中贡献。)

  • sys.path 不再接受字节。在 Python 3.2 和 3.6 之间某个时候,字节支持中断了,直到 Python 3.10.0 发布后才有人注意到。此外,由于 -bsys.path_importer_cachestrbytes 键混合时会发生交互,恢复支持会很麻烦。(由 Thomas Grainger 在 gh-91181 中贡献。)

其他 CPython 实现变更

新模块

改进的模块

asyncio

contextlib

  • 添加了非并行安全的 chdir() 上下文管理器,用于更改当前工作目录并在退出时恢复。它是 chdir() 的简单包装器。(由 Filipe Laíns 在 bpo-25625 中贡献)

dataclasses

  • 更改字段默认值可变性检查,只允许 可哈希 的默认值,而不是任何不是 dictlistset 实例的对象。(由 Eric V. Smith 在 bpo-44674 中贡献。)

datetime

enum

  • EnumMeta 重命名为 EnumTypeEnumMeta 仍保留为别名)。

  • 添加了 StrEnum,其成员可以用作(且必须是)字符串。

  • 添加了 ReprEnum,它只修改成员的 __repr__(),同时为 __str__()__format__()(由 str()format()f-string 使用)返回其字面值(而不是名称)。

  • 更改了 Enum.__format__()format()str.format()f-string 的默认值)以始终产生与 Enum.__str__() 相同的结果:对于继承自 ReprEnum 的枚举,它将是成员的值;对于所有其他枚举,它将是枚举和成员名称(例如 Color.RED)。

  • Flag 枚举和 FlagBoundary 枚举添加了新的 boundary 类参数及其选项,以控制如何处理超出范围的标志值。

  • 添加了 verify() 枚举装饰器和 EnumCheck 枚举及其选项,用于根据几个特定约束检查枚举类。

  • 添加了 member()nonmember() 装饰器,以确保被装饰的对象是/不是枚举成员。

  • 添加了 property() 装饰器,它像 property() 一样工作,但用于枚举。使用它而不是 types.DynamicClassAttribute()

  • 添加了 global_enum() 枚举装饰器,它调整 __repr__()__str__(),以将值显示为模块的成员,而不是枚举类。例如,re.RegexFlagASCII 成员显示为 're.ASCII',而不是 'RegexFlag.ASCII'

  • 增强了 Flag 以支持对其成员使用 len()、迭代和 in/not in。例如,现在以下代码可以工作:len(AFlag(3)) == 2 and list(AFlag(3)) == (AFlag.ONE, AFlag.TWO)

  • 更改了 EnumFlag,以便在调用 __init_subclass__() 之前定义成员;dir() 现在包含来自混合数据类型的方法等。

  • 更改了 Flag,使其只将主要值(2 的幂)视为规范值,而将复合值(3610 等)视为别名;反转的标志会强制转换为其正等效值。

fcntl

  • 在 FreeBSD 上,支持 F_DUP2FDF_DUP2FD_CLOEXEC 标志,前者等同于 dup2 用法,后者则额外设置了 FD_CLOEXEC 标志。

fractions

  • 支持 PEP 515 风格的字符串初始化 Fraction。(由 Sergey B Kirpichev 在 bpo-44258 中贡献。)

  • Fraction 现在实现了 __int__ 方法,因此 isinstance(some_fraction, typing.SupportsInt) 检查可以通过。(由 Mark Dickinson 在 bpo-44547 中贡献。)

functools

  • functools.singledispatch() 现在支持将 types.UnionTypetyping.Union 作为调度参数的注解。

    >>> from functools import singledispatch
    >>> @singledispatch
    ... def fun(arg, verbose=False):
    ...     if verbose:
    ...         print("Let me just say,", end=" ")
    ...     print(arg)
    ...
    >>> @fun.register
    ... def _(arg: int | float, verbose=False):
    ...     if verbose:
    ...         print("Strength in numbers, eh?", end=" ")
    ...     print(arg)
    ...
    >>> from typing import Union
    >>> @fun.register
    ... def _(arg: Union[list, set], verbose=False):
    ...     if verbose:
    ...         print("Enumerate this:")
    ...     for i, elem in enumerate(arg):
    ...         print(i, elem)
    ...
    

    (由 Yurii Karabas 在 bpo-46014 中贡献。)

gzip

  • gzip.compress() 函数与 mtime=0 参数一起使用时,速度更快,因为它将压缩完全委托给单个 zlib.compress() 操作。此更改有一个副作用:gzip 文件头包含一个“OS”字节。传统上,gzip 模块总是将其设置为代表“未知”的值 255。现在,当使用 mtime=0 调用 compress() 时,它可能会被 Python 链接到的底层 zlib C 库设置为不同的值。(有关副作用的详细信息,请参阅 gh-112346。)

hashlib

  • hashlib.blake2b()hashlib.blake2s() 现在更喜欢 libb2,而不是 Python 内置的副本。(由 Christian Heimes 在 bpo-47095 中贡献。)

  • SHA3 和 SHAKE 算法的内部 _sha3 模块现在使用 *tiny_sha3* 而不是 *Keccak Code Package*,以减少代码和二进制大小。hashlib 模块更喜欢 OpenSSL 中优化的 SHA3 和 SHAKE 实现。此更改仅影响没有 OpenSSL 支持的安装。(由 Christian Heimes 在 bpo-47098 中贡献。)

  • 添加了 hashlib.file_digest(),一个用于高效哈希文件或类文件对象的辅助函数。(由 Christian Heimes 在 gh-89313 中贡献。)

IDLE 和 idlelib

  • .pyi 文件应用语法高亮。(由 Alex Waygood 和 Terry Jan Reedy 在 bpo-45447 中贡献。)

  • 保存带输入和输出的 Shell 时包含提示。(由 Terry Jan Reedy 在 gh-95191 中贡献。)

inspect

locale

logging

math

  • 添加 math.exp2():返回 2 的 x 次幂。(由 Gideon Mitchell 在 bpo-45917 中贡献。)

  • 添加 math.cbrt():返回 x 的立方根。(由 Ajith Ramachandran 在 bpo-44357 中贡献。)

  • 为了与 IEEE 754 规范保持一致,更改了两个 math.pow() 角点情况的行为。操作 math.pow(0.0, -math.inf)math.pow(-0.0, -math.inf) 现在返回 inf。以前它们会引发 ValueError。(由 Mark Dickinson 在 bpo-44339 中贡献。)

  • math.nan 值现在始终可用。(由 Victor Stinner 在 bpo-46917 中贡献。)

operator

  • 添加了一个新函数 operator.call,使得 operator.call(obj, *args, **kwargs) == obj(*args, **kwargs)。(由 Antony Lee 在 bpo-44019 中贡献。)

os

  • 在 Windows 上,os.urandom() 现在使用 BCryptGenRandom(),而不是已废弃的 CryptGenRandom()。(由 Donghee Na 在 bpo-44611 中贡献。)

pathlib

re

  • 原子分组 ((?>...)) 和占有式量词 (*+, ++, ?+, {m,n}+) 现在在正则表达式中受支持。(由 Jeffrey C. Jacobs 和 Serhiy Storchaka 在 bpo-433030 中贡献。)

shutil

socket

sqlite3

string

sys

  • sys.exc_info() 现在从 value (异常实例) 派生 typetraceback 字段,因此当异常在处理过程中被修改时,这些更改会反映在后续调用 exc_info() 的结果中。(由 Irit Katriel 在 bpo-45711 中贡献)。

  • 添加 sys.exception(),它返回活动的异常实例 (等同于 sys.exc_info()[1])。(由 Irit Katriel 在 bpo-46328 中贡献)。

  • 添加 sys.flags.safe_path 标志。(由 Victor Stinner 在 gh-57684 中贡献)。

sysconfig

  • 新增了三个 安装方案(*posix_venv*、*nt_venv* 和 *venv*),它们在 Python 创建新的虚拟环境或从虚拟环境运行时使用。前两个方案(*posix_venv* 和 *nt_venv*)是针对非 Windows 和 Windows 的操作系统特定方案,而 *venv* 实际上是根据 Python 运行的操作系统而对其中一个方案的别名。这对于修改 sysconfig.get_preferred_scheme() 的下游分发商非常有用。创建新虚拟环境的第三方代码应使用新的 *venv* 安装方案来确定路径,就像 venv 所做的那样。(由 Miro Hrončok 在 bpo-45413 中贡献)。

tempfile

threading

时间

  • 在 Unix 上,time.sleep() 现在使用 clock_nanosleep()nanosleep() 函数(如果可用),其分辨率为 1 纳秒(10-9 秒),而不是使用分辨率为 1 微秒(10-6 秒)的 select()。(由 Benjamin Szőke 和 Victor Stinner 在 bpo-21302 中贡献)。

  • 在 Windows 8.1 及更高版本中,time.sleep() 现在使用基于 高分辨率计时器 的可等待计时器,其分辨率为 100 纳秒(10-7 秒)。之前,它的分辨率为 1 毫秒(10-3 秒)。(由 Benjamin Szőke、Donghee Na、Eryk Sun 和 Victor Stinner 在 bpo-21302bpo-45429 中贡献)。

tkinter

  • 添加了方法 info_patchlevel(),它以与 sys.version_info 类似的具名元组形式返回 Tcl 库的精确版本。(由 Serhiy Storchaka 在 gh-91827 中贡献)。

traceback

typing

有关主要更改,请参见 与类型提示相关的新特性

  • 添加 typing.assert_never()typing.Nevertyping.assert_never() 对于要求类型检查器确认一行代码不可达很有用。在运行时,它会引发 AssertionError。(由 Jelle Zijlstra 在 gh-90633 中贡献)。

  • 添加 typing.reveal_type()。这对于要求类型检查器推断给定表达式的类型很有用。在运行时,它会打印接收值的类型。(由 Jelle Zijlstra 在 gh-90572 中贡献)。

  • 添加 typing.assert_type()。这对于要求类型检查器确认其推断的给定表达式的类型与给定类型匹配很有用。在运行时,它只是返回接收到的值。(由 Jelle Zijlstra 在 gh-90638 中贡献)。

  • typing.TypedDict 类型现在可以是泛型的。(由 Samodya Abeysiriwardane 在 gh-89026 中贡献)。

  • NamedTuple 类型现在可以是泛型的。(由 Serhiy Storchaka 在 bpo-43923 中贡献)。

  • 允许 typing.Any 的子类化。这对于避免与高度动态类(例如模拟对象)相关的类型检查器错误很有用。(由 Shantanu Jain 在 gh-91154 中贡献)。

  • typing.final() 装饰器现在在被装饰的对象上设置 __final__ 属性。(由 Jelle Zijlstra 在 gh-90500 中贡献)。

  • typing.get_overloads() 函数可用于内省函数的重载。typing.clear_overloads() 可用于清除函数的所有已注册重载。(由 Jelle Zijlstra 在 gh-89263 中贡献)。

  • Protocol 子类的 __init__() 方法现在得以保留。(由 Adrian Garcia Badarasco 在 gh-88970 中贡献)。

  • 空元组类型 (Tuple[()]) 的表示被简化。这会影响内省,例如 get_args(Tuple[()]) 现在求值为 () 而不是 ((),)。(由 Serhiy Storchaka 在 gh-91137 中贡献)。

  • 通过移除私有 typing._type_check 函数中的可调用检查,放宽了类型注释的运行时要求。(由 Gregory Beauregard 在 gh-90802 中贡献)。

  • typing.get_type_hints() 现在支持在 PEP 585 泛型别名 中将字符串评估为前向引用。(由 Niklas Rosenstein 在 gh-85542 中贡献)。

  • typing.get_type_hints() 不再向默认值为 None 的参数添加 Optional。(由 Nikita Sobolev 在 gh-90353 中贡献)。

  • typing.get_type_hints() 现在支持评估裸字符串化 ClassVar 注释。(由 Gregory Beauregard 在 gh-90711 中贡献)。

  • typing.no_type_check() 不再修改外部类和函数。它现在也正确地将类方法标记为不进行类型检查。(由 Nikita Sobolev 在 gh-90729 中贡献)。

unicodedata

  • Unicode 数据库已更新至版本 14.0.0。(由 Benjamin Peterson 在 bpo-45190 中贡献)。

unittest

venv

  • 创建新的 Python 虚拟环境时,会使用 *venv* sysconfig 安装方案 来确定环境内的路径。当 Python 在虚拟环境中运行时,相同的安装方案是默认的。这意味着下游分发商可以在不改变虚拟环境行为的情况下更改默认的 sysconfig 安装方案。创建新虚拟环境的第三方代码也应该这样做。(由 Miro Hrončok 在 bpo-45413 中贡献)。

warnings

zipfile

优化

本节介绍与 更快的 CPython 项目无关的特定优化,该项目在单独的章节中介绍。

  • 编译器现在优化了字符串字面量中只包含格式代码 %s%r%a 的简单 printf 风格的 % 格式化,使其与相应的 f 字符串 表达式一样快。(由 Serhiy Storchaka 在 bpo-28307 中贡献)。

  • 整数除法 (//) 更好地针对编译器优化进行了调整。在 x86-64 上,当用小于 2**30 的值除以 int 时,它的速度现在提高了大约 20%。(由 Gregory P. Smith 和 Tim Peters 在 gh-90564 中贡献)。

  • 对于小于 2**30 的整数,sum() 现在快了近 30%。(由 Stefan Behnel 在 gh-68264 中贡献)。

  • 列表大小调整在常见情况下得到了优化,将 list.append() 的速度提高了约 15%,简单的 列表推导式 提高了 20-30%。(由 Dennis Sweeney 在 gh-91165 中贡献)。

  • 当所有键都是 Unicode 对象时,字典不再存储哈希值,从而减小了 dict 的大小。例如,在 64 位平台上,sys.getsizeof(dict.fromkeys("abcdefg")) 从 352 字节减少到 272 字节(小 23%)。(由 Inada Naoki 在 bpo-46845 中贡献)。

  • 在使用 asyncio.DatagramProtocol 通过 UDP 传输大文件时,现在速度快了几个数量级,对于约 60 MiB 的文件,速度提高了 100 多倍。(由 msoxzw 在 gh-91487 中贡献)。

  • math 函数 comb()perm() 对于大参数现在快了约 10 倍(对于更大的 *k*,加速更大)。(由 Serhiy Storchaka 在 bpo-37295 中贡献)。

  • statistics 函数 mean()variance()stdev() 现在以一次性遍历的方式消耗迭代器,而不是先将其转换为 list。这使速度提高了一倍,并可以节省大量内存。(由 Raymond Hettinger 在 gh-90415 中贡献)。

  • unicodedata.normalize() 现在以常数时间规范化纯 ASCII 字符串。(由 Donghee Na 在 bpo-44987 中贡献)。

更快的 CPython

在 Ubuntu Linux 上使用 GCC 编译时,CPython 3.11 在 pyperformance 基准测试套件中,平均比 CPython 3.10 快 25%。根据您的工作负载,整体加速可能在 10-60% 之间。

该项目专注于 Python 的两个主要领域:更快的启动更快的运行时。不在此项目范围内的优化将在 优化 部分单独列出。

更快的启动

冻结导入 / 静态代码对象

Python 将 字节码 缓存在 __pycache__ 目录中,以加快模块加载。

以前在 3.10 中,Python 模块执行过程如下

Read __pycache__ -> Unmarshal -> Heap allocated code object -> Evaluate

在 Python 3.11 中,Python 启动所需的核心模块是“冻结”的。这意味着它们的 代码对象(和字节码)由解释器静态分配。这减少了模块执行过程中的步骤,变为

Statically allocated code object -> Evaluate

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 中贡献)。

(由 Mark Shannon 在 bpo-44590 中贡献)。

内联 Python 函数调用

在 Python 函数调用期间,Python 将调用一个求值 C 函数来解释该函数的代码。这有效地将纯 Python 递归限制在 C 栈的安全范围内。

在 3.11 中,当 CPython 检测到 Python 代码调用另一个 Python 函数时,它会设置一个新帧,并“跳到”新帧中的新代码。这完全避免了调用 C 解释函数。

大多数 Python 函数调用现在不消耗 C 栈空间,从而加快了它们的速度。在简单的递归函数(如斐波那契或阶乘)中,我们观察到 1.7 倍的加速。这也意味着递归函数可以递归更深(如果用户使用 sys.setrecursionlimit() 增加了递归限制)。我们在 pyperformance 中测量到 1-3% 的改进。

(由 Pablo Galindo 和 Mark Shannon 在 bpo-45256 中贡献)。

PEP 659: 特化自适应解释器

PEP 659 是 Faster CPython 项目的关键部分之一。其基本思想是,尽管 Python 是一种动态语言,但大多数代码都有对象和类型很少变化的区域。这个概念被称为 *类型稳定性*。

在运行时,Python 将尝试在执行代码中寻找常见模式和类型稳定性。然后,Python 将当前操作替换为更专业的特殊操作。这种特殊操作使用只有这些用例/类型才可用的快速路径,通常比其通用对应项表现更好。这还引入了另一个概念,称为 *内联缓存*,其中 Python 将昂贵操作的结果直接缓存在 字节码 中。

特化器还将某些常见的指令对组合成一个超指令,从而减少执行期间的开销。

Python 只会在看到“热”代码(执行多次)时进行特化。这可以防止 Python 浪费时间在一次性代码上。当代码过于动态或用途发生变化时,Python 也可以取消特化。特化会定期尝试,并且特化尝试的成本不高,这使得特化能够适应新情况。

(PEP 由 Mark Shannon 编写,灵感来自 Stefan Brunthaler 的想法。有关更多信息,请参见 PEP 659。由 Mark Shannon 和 Brandt Bucher 实现,Irit Katriel 和 Dennis Sweeney 提供了额外帮助)。

操作

形式

专业化

操作加速 (最高)

贡献者

二元运算

x + x

x - x

x * x

常用类型(如 intfloatstr)的二元加法、乘法和减法采用其底层类型的自定义快速路径。

10%

Mark Shannon, Donghee Na, Brandt Bucher, Dennis Sweeney

下标

a[i]

下标容器类型,例如 listtupledict,直接索引底层数据结构。

自定义 __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

类似于加载属性优化。

在 pyperformance 中提高 2%

Mark Shannon

解包序列

*seq

针对常见的容器(例如 listtuple)进行了优化。避免了内部调用约定。

8%

Brandt Bucher

其他

  • 由于惰性创建的对象命名空间,对象现在需要更少的内存。它们的命名空间字典现在也更自由地共享键。(由 Mark Shannon 在 bpo-45340bpo-40116 中贡献)。

  • 实现了“零成本”异常,消除了在未引发异常时 try 语句的开销。(由 Mark Shannon 在 bpo-40222 中贡献)。

  • 解释器中更简洁的异常表示将捕获异常所需的时间减少了约 10%。(由 Irit Katriel 在 bpo-45711 中贡献)。

  • re 的正则表达式匹配引擎已部分重构,现在在支持的平台上使用计算 goto(或“线程代码”)。因此,Python 3.11 执行 pyperformance 正则表达式基准测试 的速度比 Python 3.10 快 10%。(由 Brandt Bucher 在 gh-91404 中贡献)。

常见问题

我应该如何编写代码来利用这些加速?

编写遵循常见最佳实践的 Pythonic 代码;您无需更改代码。Faster CPython 项目优化了我们观察到的常见代码模式。

CPython 3.11 会使用更多内存吗?

可能不会;我们预计内存使用量不会超过 3.10 的 20%。这可以通过上面提到的帧对象和对象字典的内存优化来抵消。

我的工作负载中没有看到任何加速。为什么?

某些代码不会有明显的收益。如果您的代码大部分时间花在 I/O 操作上,或者大部分计算已经在 NumPy 等 C 扩展库中完成,则不会有显著的加速。该项目目前对纯 Python 工作负载的收益最大。

此外,pyperformance 的数据是几何平均值。即使在 pyperformance 基准测试中,某些基准测试略有减慢,而另一些则加速了近 2 倍!

有 JIT 编译器吗?

没有。我们仍在探索其他优化。

关于

Faster CPython 探索了 CPython 的优化。主要团队由微软资助,全职从事这项工作。Pablo Galindo Salgado 也由 Bloomberg LP 资助,兼职从事该项目。最后,许多贡献者是社区的志愿者。

CPython 字节码变更

字节码现在包含内联缓存条目,它们以新添加的 CACHE 指令的形式存在。许多操作码期望后面跟着确切数量的缓存,并指示解释器在运行时跳过它们。填充的缓存可以看起来像任意指令,因此在读取或修改包含加速数据的原始、自适应字节码时应格外小心。

新操作码

替换的操作码

替换的操作码

新操作码

备注

BINARY_*
INPLACE_*

BINARY_OP

将所有数值二元/原地操作码替换为单个操作码

CALL_FUNCTION
CALL_FUNCTION_KW
CALL_METHOD
KW_NAMES
PRECALL

将方法的参数移位与关键字参数处理解耦;允许更好的调用特化

DUP_TOP
DUP_TOP_TWO
ROT_TWO
ROT_THREE
ROT_FOUR
ROT_N

栈操作指令

JUMP_IF_NOT_EXC_MATCH

现在执行检查但不跳转

JUMP_ABSOLUTE
POP_JUMP_IF_FALSE
POP_JUMP_IF_TRUE
POP_JUMP_BACKWARD_IF_*
POP_JUMP_FORWARD_IF_*

参见 [3];每个方向的 TRUEFALSENONENOT_NONE 变体

SETUP_WITH
SETUP_ASYNC_WITH

BEFORE_WITH

with 块设置

更改/移除的操作码

  • 更改了 MATCH_CLASSMATCH_KEYS,使其不再推送一个额外的布尔值来指示成功/失败。相反,在失败时,会推送 None 来代替提取值的元组。

  • 更改了处理异常的操作码,以反映它们现在在栈上表示为一个项,而不是三个项(请参阅 gh-89874)。

  • 移除了 COPY_DICT_WITHOUT_KEYSGEN_STARTPOP_BLOCKSETUP_FINALLYYIELD_FROM

已弃用

本节列出了 Python 3.11 中已弃用的 Python API。

已弃用的 C API 单独列出

语言/内置

  • 链接 classmethod 描述符(在 bpo-19072 中引入)现在已弃用。它不能再用于包装其他描述符,例如 property。此功能的核心设计存在缺陷,并导致了一些下游问题。要“传递”一个 classmethod,请考虑使用 Python 3.10 中添加的 __wrapped__ 属性。(由 Raymond Hettinger 在 gh-89519 中贡献)。

  • 字符串和字节字面量中八进制转义符的值大于 0o377(十进制 255)现在会产生 DeprecationWarning。在未来的 Python 版本中,它们将引发 SyntaxWarning,并最终引发 SyntaxError。(由 Serhiy Storchaka 在 gh-81548 中贡献)。

  • int()__trunc__() 的委托现在已弃用。当 type(a) 实现了 __trunc__() 但没有实现 __int__()__index__() 时,调用 int(a) 现在会引发 DeprecationWarning。(由 Zackery Spytz 在 bpo-44977 中贡献)。

模块

  • PEP 594 导致以下模块被弃用,并计划在 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 和 Victor Stinner 在 gh-68966 中贡献)。

  • asynchatasyncoresmtpd 模块自 Python 3.6 以来已被弃用。它们的文档和弃用警告已更新,以指出它们将在 Python 3.12 中移除。(由 Hugo van Kemenade 在 bpo-47022 中贡献)。

  • lib2to3 包和 2to3 工具现已弃用,可能无法解析 Python 3.10 或更高版本。有关详细信息,请参见引入新 PEG 解析器的 PEP 617。(由 Victor Stinner 在 bpo-40360 中贡献)。

  • 未文档化的模块 sre_compilesre_constantssre_parse 现已弃用。(由 Serhiy Storchaka 在 bpo-47152 中贡献)。

标准库

  • 以下内容已在 configparser 中自 Python 3.2 以来被弃用。它们的弃用警告现已更新,以指出它们将在 Python 3.12 中移除:

    • configparser.SafeConfigParser

    • configparser.ParsingError.filename 属性

    • configparser.RawConfigParser.readfp() 方法

    (由 Hugo van Kemenade 在 bpo-45173 中贡献)。

  • configparser.LegacyInterpolation 自 Python 3.2 以来在文档字符串中已弃用,并且未在 configparser 文档中列出。它现在会发出 DeprecationWarning,并将在 Python 3.13 中移除。请改用 configparser.BasicInterpolationconfigparser.ExtendedInterpolation。(由 Hugo van Kemenade 在 bpo-46607 中贡献)。

  • 较旧的 importlib.resources 函数集已弃用,取而代之的是 Python 3.9 中添加的新函数,并且将在未来的 Python 版本中移除,因为它们不支持包子目录中的资源:

    • 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 中贡献)。

  • locale.resetlocale() 函数已弃用,并将在 Python 3.13 中移除。请改用 locale.setlocale(locale.LC_ALL, "")。(由 Victor Stinner 在 gh-90817 中贡献)。

  • 现在,针对 正则表达式 中的数字组引用和组名将应用更严格的规则。现在,只有 ASCII 数字序列才会被接受为数字引用,并且 bytes 模式和替换字符串中的组名只能包含 ASCII 字母、数字和下划线。目前,违反这些规则的语法会引发弃用警告。(由 Serhiy Storchaka 在 gh-91760 中贡献)。

  • re 模块中,re.template() 函数以及相应的 re.TEMPLATEre.T 标志已弃用,因为它们未文档化且缺乏明确的目的。它们将在 Python 3.13 中移除。(由 Serhiy Storchaka 和 Miro Hrončok 在 gh-92728 中贡献)。

  • turtle.settiltangle() 自 Python 3.1 以来已被弃用;它现在会发出弃用警告,并将在 Python 3.13 中移除。请改用 turtle.tiltangle()(它之前被错误地标记为已弃用,现在其文档字符串已更正)。(由 Hugo van Kemenade 在 bpo-45837 中贡献)。

  • typing.Text 仅用于提供 Python 2 和 Python 3 代码之间的兼容性支持,现已弃用。目前尚未计划将其移除,但鼓励用户在可能的情况下使用 str。(由 Alex Waygood 在 gh-92332 中贡献)。

  • 用于构建 typing.TypedDict 类型的关键字参数语法现已弃用。Python 3.13 中将移除支持。(由 Jingchen Ye 在 gh-90224 中贡献)。

  • webbrowser.MacOSX 已弃用,并将在 Python 3.13 中移除。它未经测试,未文档化,并且 webbrowser 本身不使用它。(由 Donghee Na 在 bpo-42255 中贡献)。

  • TestCaseIsolatedAsyncioTestCase 测试方法返回非默认 None 值的行为现在已被弃用。

  • 弃用了以下未正式文档化的 unittest 函数,计划在 Python 3.13 中移除:

    • unittest.findTestCases()

    • unittest.makeSuite()

    • unittest.getTestCaseNames()

    请改用 TestLoader 方法:

    (由 Erlend E. Aasland 在 bpo-5846 中贡献)。

  • unittest.TestProgram.usageExit() 被标记为已弃用,将在 3.13 中移除。(由 Carlos Damázio 在 gh-67048 中贡献)。

计划在 Python 3.12 中移除

以下 Python API 已在之前的 Python 版本中弃用,并将在 Python 3.12 中移除。

计划移除的 C API 单独列出

  • asynchat 模块

  • asyncore 模块

  • 整个 distutils 包

  • 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 环境变量

  • 以下 unittest 中已弃用的别名:

    已弃用的别名

    方法名

    弃用版本

    failUnless

    assertTrue()

    3.1

    failIf

    assertFalse()

    3.1

    failUnlessEqual

    assertEqual()

    3.1

    failIfEqual

    assertNotEqual()

    3.1

    failUnlessAlmostEqual

    assertAlmostEqual()

    3.1

    failIfAlmostEqual

    assertNotAlmostEqual()

    3.1

    failUnlessRaises

    assertRaises()

    3.1

    assert_

    assertTrue()

    3.2

    assertEquals

    assertEqual()

    3.2

    assertNotEquals

    assertNotEqual()

    3.2

    assertAlmostEquals

    assertAlmostEqual()

    3.2

    assertNotAlmostEquals

    assertNotAlmostEqual()

    3.2

    assertRegexpMatches

    assertRegex()

    3.2

    assertRaisesRegexp

    assertRaisesRegex()

    3.2

    assertNotRegexpMatches

    assertNotRegex()

    3.5

已移除

本节列出了 Python 3.11 中已移除的 Python API。

已移除的 C API 单独列出

  • 移除了 @asyncio.coroutine() 装饰器,该装饰器曾使基于旧版生成器的协程能够与 async / await 代码兼容。此函数自 Python 3.8 起已被弃用,并原定于 Python 3.10 中移除。请改用 async def。(由 Illia Volochii 在 bpo-43216 中贡献。)

  • 移除了 asyncio.coroutines.CoroWrapper,该类用于在调试模式下包装基于旧版生成器的协程对象。(由 Illia Volochii 在 bpo-43216 中贡献。)

  • 由于重大的安全问题,asyncio.loop.create_datagram_endpoint()reuse_address 参数(在 Python 3.9 中禁用)现在已完全移除。这是由于 SO_REUSEADDR 套接字选项在 UDP 中的行为所致。(由 Hugo van Kemenade 在 bpo-45129 中贡献。)

  • 移除了 binhex 模块,该模块在 Python 3.9 中已被弃用。同时移除了相关且同样已被弃用的 binascii 函数:

    • binascii.a2b_hqx()

    • binascii.b2a_hqx()

    • binascii.rlecode_hqx()

    • binascii.rldecode_hqx()

    binascii.crc_hqx() 函数仍然可用。

    (由 Victor Stinner 在 bpo-45085 中贡献。)

  • 移除了 distutilsbdist_msi 命令,该命令在 Python 3.9 中已被弃用。请改用 bdist_wheel (wheel 包)。(由 Hugo van Kemenade 在 bpo-45124 中贡献。)

  • 移除了 xml.dom.pulldom.DOMEventStreamwsgiref.util.FileWrapperfileinput.FileInput__getitem__() 方法,这些方法自 Python 3.9 起已被弃用。(由 Hugo van Kemenade 在 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 中贡献。)

  • inspect 模块中移除:

    (由 Hugo van Kemenade 在 bpo-45320 中贡献。)

  • pathlib.PurePath 中移除了 __class_getitem__() 方法,因为它未被使用且在早期版本中因错误而添加。(由 Nikita Sobolev 在 bpo-46483 中贡献。)

  • 移除了 smtpd 模块中的 MailmanProxy 类,因为它在没有外部 mailman 包的情况下无法使用。(由 Donghee Na 在 bpo-35800 中贡献。)

  • 移除了 _tkinter.TkappType 中已弃用的 split() 方法。(由 Erlend E. Aasland 在 bpo-38371 中贡献。)

  • 移除了 unittest 发现功能中的命名空间包支持。该功能在 Python 3.4 中引入,但自 Python 3.7 起已损坏。(由 Inada Naoki 在 bpo-23882 中贡献。)

  • 移除了未文档化的私有 float.__set_format__() 方法,该方法在 Python 3.7 中曾被称为 float.__setformat__()。其文档字符串写道:“您可能不想使用此函数。它主要用于 Python 的测试套件。”(由 Victor Stinner 在 bpo-46852 中贡献。)

  • --experimental-isolated-subinterpreters 配置标志(以及相应的 EXPERIMENTAL_ISOLATED_SUBINTERPRETERS 宏)已被移除。

  • Pynche —— Pythonic自然色彩和色调编辑器 —— 已从 Tools/scripts 移出,并 独立于 Python 源代码树进行开发

移植到 Python 3.11

本节列出了之前描述的更改以及 Python API 中可能需要更改您的 Python 代码的其他错误修复。

C API 的移植说明 单独列出

构建更改

  • CPython 现在对 WebAssembly 平台 Emscripten (wasm32-unknown-emscripten,即浏览器中的 Python) 和 WebAssembly 系统接口 (WASI) (wasm32-unknown-wasi) 具有 PEP 11 Tier 3 支持 的交叉编译功能。此工作受到 Pyodide 等先前工作的启发。这些平台提供了 POSIX API 的有限子集;与网络、进程、线程、信号、mmap 和用户/组相关的 Python 标准库功能和模块不可用或不起作用。(Emscripten 由 Christian Heimes 和 Ethan Smith 在 gh-84461 中贡献,WASI 由 Christian Heimes 在 gh-90473 中贡献;平台在 gh-95085 中得到推广)

  • 构建 CPython 现在需要

  • 已移除 Py_NO_NAN 宏。由于 CPython 现在需要 IEEE 754 浮点数,因此 NaN 值始终可用。(由 Victor Stinner 在 bpo-46656 中贡献。)

  • tkinter 包现在需要 Tcl/Tk 8.5.12 或更高版本。(由 Serhiy Storchaka 在 bpo-46996 中贡献。)

  • 大多数 stdlib 扩展模块的构建依赖项、编译器标志和链接器标志现在由 configure 检测。libffi、libnsl、libsqlite3、zlib、bzip2、liblzma、libcrypt、Tcl/Tk 和 uuid 标志由 pkg-config(如果可用)检测。tkinter 现在需要 pkg-config 命令来检测 Tcl/Tk 头文件和库的开发设置。(由 Christian Heimes 和 Erlend Egeberg Aasland 在 bpo-45847bpo-45747bpo-45763 中贡献。)

  • libpython 不再链接 libcrypt。(由 Mike Gilbert 在 bpo-45433 中贡献。)

  • CPython 现在可以通过向 --with-lto 传递 thin 选项,即 --with-lto=thin,来使用 ThinLTO 选项构建。(由 Donghee Na 和 Brett Holman 在 bpo-44340 中贡献。)

  • 现在可以禁用对象结构的空闲列表。新的 configure 选项 --without-freelists 可用于禁用除空元组单例之外的所有空闲列表。(由 Christian Heimes 在 bpo-45522 中贡献。)

  • Modules/SetupModules/makesetup 已得到改进和整合。现在可以通过 makesetup 构建扩展模块。除了一些测试模块外,所有模块都可以静态链接到主二进制文件或库中。(由 Brett Cannon 和 Christian Heimes 在 bpo-45548bpo-45570bpo-45571bpo-43974 中贡献。)

    备注

    使用环境变量 TCLTK_CFLAGSTCLTK_LIBS 手动指定 Tcl/Tk 头文件和库的位置。configure 选项 --with-tcltk-includes--with-tcltk-libs 已被移除。

    在 RHEL 7 和 CentOS 7 上,开发包不提供 tcl.pctk.pc;请使用 TCLTK_LIBS="-ltk8.5 -ltkstub8.5 -ltcl8.5"。目录 Misc/rhel7 包含 .pc 文件以及如何使用 RHEL 7 和 CentOS 7 的 Tcl/Tk 和 OpenSSL 构建 Python 的说明。

  • CPython 现在默认将对 Python int 实现使用 30 位数字。此前,默认是在 SIZEOF_VOID_P >= 8 的平台上使用 30 位数字,否则使用 15 位数字。仍然可以通过配置脚本的 --enable-big-digits 选项或(对于 Windows)PC/pyconfig.h 中的 PYLONG_BITS_IN_DIGIT 变量显式请求使用 15 位数字,但此选项可能会在未来的某个时候移除。(由 Mark Dickinson 在 bpo-45569 中贡献。)

C API 更改

新功能

移植到 Python 3.11

  • 一些宏已转换为静态内联函数,以避免 宏陷阱。此更改对用户而言应基本透明,因为替换函数将把其参数转换为预期类型,以避免由于静态类型检查导致的编译器警告。然而,当受限 C API 设置为 >=3.11 时,这些转换不会进行,调用者需要将参数转换为预期类型。有关更多详细信息,请参阅 PEP 670。(由 Victor Stinner 和 Erlend E. Aasland 在 gh-89653 中贡献。)

  • PyErr_SetExcInfo() 不再使用 typetraceback 参数,解释器现在从异常实例(value 参数)派生这些值。该函数仍然窃取所有三个参数的引用。(由 Irit Katriel 在 bpo-45711 中贡献。)

  • PyErr_GetExcInfo() 现在从异常实例(value 字段)派生结果的 typetraceback 字段。(由 Irit Katriel 在 bpo-45711 中贡献。)

  • _frozen 有一个新的 is_package 字段,用于指示冻结模块是否为包。此前,size 字段中的负值是指示符。现在 size 将只使用非负值。(由 Kumar Aditya 在 bpo-46608 中贡献。)

  • _PyFrameEvalFunction() 现在将其第二个参数从 PyFrameObject* 改为 _PyInterpreterFrame*。有关如何使用此函数指针类型的更多详细信息,请参阅 PEP 523

  • PyCode_New()PyCode_NewWithPosOnlyArgs() 现在接受一个额外的 exception_table 参数。应尽可能避免使用这些函数。要获取自定义代码对象:使用编译器创建一个代码对象,然后使用 replace 方法获取修改后的版本。

  • PyCodeObject 不再有 co_codeco_varnamesco_cellvarsco_freevars 字段。请改用 PyCode_GetCode()PyCode_GetVarnames()PyCode_GetCellvars()PyCode_GetFreevars() 分别通过 C API 访问它们。(由 Brandt Bucher 在 bpo-46841 和 Ken Jin 在 gh-92154gh-94936 中贡献。)

  • 旧的垃圾桶宏 (Py_TRASHCAN_SAFE_BEGIN/Py_TRASHCAN_SAFE_END) 现已弃用。它们应替换为新的宏 Py_TRASHCAN_BEGINPy_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 中贡献。)

  • 具有 Py_TPFLAGS_IMMUTABLETYPE 标志的堆类型现在可以继承 PEP 590 vectorcall 协议。此前,这仅适用于 静态类型。(由 Erlend E. Aasland 在 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 _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
    { ob->ob_type = type; }
    #define Py_SET_TYPE(ob, type) _Py_SET_TYPE((PyObject*)(ob), type)
    #endif
    

    (由 Victor Stinner 在 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 _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
    { ob->ob_size = size; }
    #define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size)
    #endif
    

    (由 Victor Stinner 在 bpo-39573 中贡献。)

  • Py_LIMITED_API 宏设置为 0x030b0000 (Python 3.11) 或更高版本时,<Python.h> 不再包含头文件 <stdlib.h><stdio.h><errno.h><string.h>。C 扩展应在 #include <Python.h> 之后显式包含这些头文件。(由 Victor Stinner 在 bpo-45434 中贡献。)

  • 非受限 API 文件 cellobject.hclassobject.hcode.hcontext.hfuncobject.hgenobject.hlongintrepr.h 已移至 Include/cpython 目录。此外,eval.h 头文件已被移除。这些文件不应直接包含,因为它们已包含在 Python.h 中:包含文件。如果已直接包含它们,请考虑改用 Python.h。(由 Victor Stinner 在 bpo-35134 中贡献。)

  • PyUnicode_CHECK_INTERNED() 宏已从受限 C API 中排除。它在那里从未可用,因为它使用了受限 C API 中不可用的内部结构。(由 Victor Stinner 在 bpo-46007 中贡献。)

  • 以下帧函数和类型现在可直接通过 #include <Python.h> 使用,不再需要添加 #include <frameobject.h>

    (由 Victor Stinner 在 gh-93937 中贡献。)

  • PyFrameObject 结构成员已从公共 C API 中移除。

    虽然文档指出 PyFrameObject 字段可能随时更改,但它们已稳定很长时间,并被一些流行的扩展使用。

    在 Python 3.11 中,帧结构被重组以实现性能优化。一些字段完全移除,因为它们是旧实现中的细节。

    PyFrameObject 字段

    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 项目 在旧版 Python 上获取这两个函数。

  • PyThreadState 结构成员的更改

    在 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 项目 在旧版 Python 上获取这些函数。

  • 鼓励分发商使用优化的 Blake2 库 libb2 构建 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()

    • _Py_SetProgramFullPath()

    请改用 Python 初始化配置 的新 PyConfig API(PEP 587)。(由 Victor Stinner 在 gh-88279 中贡献。)

  • 弃用 PyBytesObjectob_shash 成员。请改用 PyObject_Hash()。(由 Inada Naoki 在 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_READY()

  • PyUnicode_WSTR_LENGTH()

  • _PyUnicode_AsUnicode()

  • PyUnicode_WCHAR_KIND

  • PyUnicodeObject

  • PyUnicode_InternImmortal()

已移除

  • PyFrame_BlockSetup()PyFrame_BlockPop() 已被移除。(由 Mark Shannon 在 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 中贡献。)

  • 移除 Py_UNICODE_COPY()Py_UNICODE_FILL() 宏,它们自 Python 3.3 起已被弃用。请改用 PyUnicode_CopyCharacters()memcpy() (wchar_t* 字符串),以及 PyUnicode_Fill() 函数。(由 Victor Stinner 在 bpo-41123 中贡献。)

  • 移除 pystrhex.h 头文件。它只包含私有函数。C 扩展只应包含主要的 <Python.h> 头文件。(由 Victor Stinner 在 bpo-45434 中贡献。)

  • 移除 Py_FORCE_DOUBLE() 宏。它曾被 Py_IS_INFINITY() 宏使用。(由 Victor Stinner 在 bpo-45440 中贡献。)

  • Py_LIMITED_API 定义时,以下项目不再可用

    这些不属于 受限 API

    (由 Victor Stinner 在 bpo-45474 中贡献。)

  • 从受限 C API 中排除 PyWeakref_GET_OBJECT()。它从未起作用,因为 PyWeakReference 结构在受限 C API 中是不透明的。(由 Victor Stinner 在 bpo-35134 中贡献。)

  • 移除 PyHeapType_GET_MEMBERS() 宏。它因错误地暴露在公共 C API 中,它只能在 Python 内部使用。请改用 PyTypeObject.tp_members 成员。(由 Victor Stinner 在 bpo-40170 中贡献。)

  • 移除 HAVE_PY_SET_53BIT_PRECISION 宏(已移至内部 C API)。(由 Victor Stinner 在 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。(由 Inada Naoki 在 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 中贡献。)

3.11.5 中的显著更改

OpenSSL

  • python.org 提供的 Windows 构建和 macOS 安装程序现在使用 OpenSSL 3.0。