Python 3.12 的新功能

编辑::

Adam Turner

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

另请参阅

PEP 693 – Python 3.12 发布时间表

摘要 – 版本亮点

Python 3.12 是 Python 编程语言的稳定版本,对语言和标准库进行了一些更改。库的更改侧重于清理已弃用的 API、可用性和正确性。值得注意的是,distutils 包已从标准库中删除。ospathlib 中的文件系统支持进行了一些改进,并且一些模块具有更好的性能。

语言更改侧重于可用性,因为 f-字符串 删除了许多限制,“你的意思是……”的建议不断改进。新的类型参数语法type语句提高了使用泛型类型类型别名以及静态类型检查器的人体工程学。

本文不尝试提供所有新功能的完整规范,而是提供方便的概述。有关完整详细信息,您应该参考文档,例如库参考语言参考。如果您想了解更改的完整实现和设计原理,请参阅特定新功能的 PEP;但请注意,一旦功能完全实现,PEP 通常不会保持最新。


新的语法功能

新的语法功能

解释器改进

Python 数据模型改进

标准库的重大改进

安全改进

  • hashlib 的内置 SHA1、SHA3、SHA2-384、SHA2-512 和 MD5 实现替换为来自 HACL* 项目的形式验证代码。这些内置实现仍然是后备方案,仅在 OpenSSL 不提供它们时使用。

C API 改进

CPython 实现改进

  • PEP 709,推导式内联

  • Linux perf 分析器的CPython 支持

  • 在受支持的平台上实现堆栈溢出保护

新的类型功能

重要的弃用、删除或限制

  • PEP 623:从 Python C API 中的 Unicode 对象中删除 wstr,从而使每个 str 对象的大小至少减少 8 个字节。

  • PEP 632: 移除 distutils 包。 请参阅 迁移指南,以获取替换其提供的 API 的建议。 如果你仍然需要在 Python 3.12 及更高版本中使用 distutils,第三方 Setuptools 包会继续提供该模块。

  • gh-95299: 在使用 venv 创建的虚拟环境中,不再预安装 setuptools。 这意味着 distutilssetuptoolspkg_resourceseasy_install 将不再默认可用;要访问这些,请在已激活的虚拟环境中运行 pip install setuptools

  • asynchatasyncoreimp 模块已被移除,同时还有几个 unittest.TestCase 方法别名

新特性

PEP 695:类型参数语法

PEP 484 下,泛型类和函数使用冗长的语法声明,这使得类型参数的作用域不明确,并且需要显式声明变异性。

PEP 695 引入了一种新的、更紧凑和明确的方式来创建 泛型类函数

def max[T](args: Iterable[T]) -> T:
    ...

class list[T]:
    def __getitem__(self, index: int, /) -> T:
        ...

    def append(self, element: T) -> None:
        ...

此外,PEP 还引入了一种使用 type 语句声明 类型别名 的新方法,该语句创建 TypeAliasType 的实例

type Point = tuple[float, float]

类型别名也可以是 泛型的

type Point[T] = tuple[T, T]

新语法允许声明 TypeVarTupleParamSpec 参数,以及具有边界或约束的 TypeVar 参数

type IntFunc[**P] = Callable[P, int]  # ParamSpec
type LabeledTuple[*Ts] = tuple[str, *Ts]  # TypeVarTuple
type HashableSequence[T: Hashable] = Sequence[T]  # TypeVar with bound
type IntOrStrSequence[T: (int, str)] = Sequence[T]  # TypeVar with constraints

通过此语法创建的类型别名的值以及类型变量的边界和约束仅在需要时进行评估(请参阅 延迟求值)。这意味着类型别名能够引用文件中稍后定义的其他类型。

通过类型参数列表声明的类型参数在声明的作用域和任何嵌套作用域内可见,但在外部作用域中不可见。例如,它们可以用于泛型类的方法的类型注释或类主体中。但是,它们不能在类定义后的模块作用域中使用。有关类型参数的运行时语义的详细描述,请参阅 类型参数列表

为了支持这些作用域语义,引入了一种新的作用域,即 注解作用域。注解作用域在大多数情况下与函数作用域的行为类似,但在与封闭的类作用域交互时会有所不同。在 Python 3.13 中,注解 也将在注解作用域中进行评估。

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

(PEP 由 Eric Traut 编写。由 Jelle Zijlstra、Eric Traut 和其他人在 gh-103764 中实现。)

PEP 701:f-字符串的句法形式化

PEP 701 取消了对 f-字符串 使用的一些限制。f-字符串内部的表达式组件现在可以是任何有效的 Python 表达式,包括重用与包含 f-字符串相同的引号的字符串、多行表达式、注释、反斜杠和 Unicode 转义序列。让我们详细介绍这些

  • 引号重用:在 Python 3.11 中,重用与封闭 f-字符串相同的引号会引发 SyntaxError,迫使用户要么使用其他可用引号(例如,如果 f-字符串使用单引号,则使用双引号或三引号)。在 Python 3.12 中,你现在可以执行以下操作

    >>> songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism']
    >>> f"This is the playlist: {", ".join(songs)}"
    'This is the playlist: Take me back to Eden, Alkaline, Ascensionism'
    

    请注意,在此更改之前,f-字符串的嵌套方式没有明确的限制,但事实上,字符串引号不能在 f-字符串的表达式组件内部重用,这使得任意嵌套 f-字符串变得不可能。事实上,这是可以编写的最嵌套的 f-字符串

    >>> f"""{f'''{f'{f"{1+1}"}'}'''}"""
    '2'
    

    由于现在 f-字符串可以在表达式组件内部包含任何有效的 Python 表达式,因此现在可以任意嵌套 f-字符串

    >>> f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}"
    '2'
    
  • 多行表达式和注释:在 Python 3.11 中,f-字符串表达式必须在单行中定义,即使 f-字符串中的表达式通常可以跨越多行(例如,在多行上定义的文字列表),这使得它们更难阅读。在 Python 3.12 中,你现在可以定义跨越多行的 f-字符串,并添加内联注释

    >>> f"This is the playlist: {", ".join([
    ...     'Take me back to Eden',  # My, my, those eyes like fire
    ...     'Alkaline',              # Not acid nor alkaline
    ...     'Ascensionism'           # Take to the broken skies at last
    ... ])}"
    'This is the playlist: Take me back to Eden, Alkaline, Ascensionism'
    
  • 反斜杠和 Unicode 字符:在 Python 3.12 之前,f-字符串表达式不能包含任何 \ 字符。这也影响了 Unicode 转义序列(例如 \N{snowman}),因为这些序列包含之前不能作为 f-字符串表达式组件一部分的 \N 部分。现在,你可以定义如下的表达式

    >>> print(f"This is the playlist: {"\n".join(songs)}")
    This is the playlist: Take me back to Eden
    Alkaline
    Ascensionism
    >>> print(f"This is the playlist: {"\N{BLACK HEART SUIT}".join(songs)}")
    This is the playlist: Take me back to Eden♥Alkaline♥Ascensionism
    

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

作为此功能实现方式的积极副作用(通过 PEG 解析器 解析 f-字符串),现在 f-字符串的错误消息更加精确,并包含错误的精确位置。例如,在 Python 3.11 中,以下 f-字符串引发 SyntaxError

>>> my_string = f"{x z y}" + f"{1 + 1}"
  File "<stdin>", line 1
    (x z y)
     ^^^
SyntaxError: f-string: invalid syntax. Perhaps you forgot a comma?

但是错误消息不包含行内错误的精确位置,并且还人为地用括号括住了表达式。在 Python 3.12 中,由于 f-字符串是通过 PEG 解析器解析的,因此错误消息可以更加精确,并显示整行

>>> my_string = f"{x z y}" + f"{1 + 1}"
  File "<stdin>", line 1
    my_string = f"{x z y}" + f"{1 + 1}"
                   ^^^
SyntaxError: invalid syntax. Perhaps you forgot a comma?

(由 Pablo Galindo、Batuhan Taskaya、Lysandros Nikolaou、Cristián Maureira-Fredes 和 Marta Gómez 在 gh-102856 中贡献。PEP 由 Pablo Galindo、Batuhan Taskaya、Lysandros Nikolaou 和 Marta Gómez 编写。)

PEP 684:每个解释器的 GIL

PEP 684 引入了每个解释器的 GIL,以便现在可以为每个解释器创建一个具有唯一 GIL 的子解释器。这允许 Python 程序充分利用多核 CPU。这目前仅通过 C-API 提供,但预计 Python API 将在 3.13 中推出

使用新的 Py_NewInterpreterFromConfig() 函数创建具有自己 GIL 的解释器

PyInterpreterConfig config = {
    .check_multi_interp_extensions = 1,
    .gil = PyInterpreterConfig_OWN_GIL,
};
PyThreadState *tstate = NULL;
PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config);
if (PyStatus_Exception(status)) {
    return -1;
}
/* The new interpreter is now active in the current thread. */

有关如何使用 C-API 为具有每个解释器 GIL 的子解释器的更多示例,请参阅 Modules/_xxsubinterpretersmodule.c

(由 Eric Snow 在 gh-104210 等中贡献。)

PEP 669:CPython 的低影响监控

PEP 669 定义了一个新的 API,用于分析器、调试器和其他工具来监控 CPython 中的事件。它涵盖了广泛的事件,包括调用、返回、行、异常、跳转等等。这意味着您只需为您使用的部分付费,为近零开销的调试器和覆盖率工具提供支持。有关详细信息,请参阅 sys.monitoring

(由 Mark Shannon 在 gh-103082 中贡献。)

PEP 688: 使缓冲区协议可在 Python 中访问

PEP 688 引入了一种从 Python 代码中使用缓冲区协议的方法。实现 __buffer__() 方法的类现在可以用作缓冲区类型。

新的 collections.abc.Buffer ABC 提供了一种表示缓冲区对象的标准方法,例如在类型注释中。新的 inspect.BufferFlags 枚举表示可用于自定义缓冲区创建的标志。(由 Jelle Zijlstra 在 gh-102500 中贡献。)

PEP 709: 推导式内联

字典、列表和集合推导式现在是内联的,而不是为每次推导式的执行创建一个新的单次使用函数对象。这使得推导式的执行速度提高了两倍。有关详细信息,请参阅 PEP 709

推导式的迭代变量仍然是隔离的,不会覆盖外部作用域中同名的变量,也不会在推导式之后可见。内联确实导致了一些可见的行为变化。

  • 回溯中不再有推导式的单独帧,并且跟踪/分析不再将推导式显示为函数调用。

  • symtable 模块将不再为每个推导式生成子符号表;相反,推导式的局部变量将包含在父函数的符号表中。

  • 在推导式内部调用 locals() 现在包括来自推导式外部的变量,并且不再包括推导式“参数”的合成 .0 变量。

  • 当在跟踪(例如代码覆盖率测量)下运行时,直接迭代 locals() 的推导式(例如 [k for k in locals()])可能会看到 “RuntimeError: dictionary changed size during iteration”。这与在例如 for k in locals(): 中看到的行为相同。要避免此错误,请先创建一个要迭代的键列表:keys = list(locals()); [k for k in keys]

(由 Carl Meyer 和 Vladimir Matveev 在 PEP 709 中贡献。)

改进的错误消息

  • 现在,当 NameError 引发到顶层时,解释器显示的错误消息中可能会建议标准库中的模块。(由 Pablo Galindo 在 gh-98254 中贡献。)

    >>> sys.version_info
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'sys' is not defined. Did you forget to import 'sys'?
    
  • 改进实例的 NameError 异常的错误建议。现在,如果在一个方法中引发 NameError,并且该实例的属性与异常中的名称完全相等,则建议将包括 self.<NAME>,而不是方法范围内的最接近的匹配项。(由 Pablo Galindo 在 gh-99139 中贡献。)

    >>> class A:
    ...    def __init__(self):
    ...        self.blech = 1
    ...
    ...    def foo(self):
    ...        somethin = blech
    ...
    >>> A().foo()
    Traceback (most recent call last):
      File "<stdin>", line 1
        somethin = blech
                   ^^^^^
    NameError: name 'blech' is not defined. Did you mean: 'self.blech'?
    
  • 当用户键入 import x from y 而不是 from y import x 时,改进 SyntaxError 错误消息。(由 Pablo Galindo 在 gh-98931 中贡献。)

    >>> import a.y.z from b.y.z
    Traceback (most recent call last):
      File "<stdin>", line 1
        import a.y.z from b.y.z
        ^^^^^^^^^^^^^^^^^^^^^^^
    SyntaxError: Did you mean to use 'from ... import ...' instead?
    
  • 从失败的 from <module> import <name> 语句引发的 ImportError 异常现在包括基于 <module> 中的可用名称的 <name> 值的建议。(由 Pablo Galindo 在 gh-91058 中贡献。)

    >>> from collections import chainmap
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ImportError: cannot import name 'chainmap' from 'collections'. Did you mean: 'ChainMap'?
    

其他语言更改

  • 现在,当解析包含空字节的源代码时,解析器会引发 SyntaxError。(由 Pablo Galindo 在 gh-96670 中贡献。)

  • 现在,不是有效的转义序列的反斜杠字符对会生成 SyntaxWarning,而不是 DeprecationWarning。例如,re.compile("\d+\.\d+") 现在会发出一个 SyntaxWarning"\d" 是无效的转义序列,对正则表达式使用原始字符串:re.compile(r"\d+\.\d+"))。在未来的 Python 版本中,最终将引发 SyntaxError,而不是 SyntaxWarning。(由 Victor Stinner 在 gh-98401 中贡献。)

  • 八进制转义符的值大于 0o377 (例如:"\477"),在 Python 3.11 中已被弃用,现在会产生一个 SyntaxWarning,而不是 DeprecationWarning。在未来的 Python 版本中,它们最终会成为一个 SyntaxError。(由 Victor Stinner 在 gh-98401 中贡献。)

  • 在推导式目标部分中使用的、未存储的变量现在可以在赋值表达式中使用(:=)。例如,在 [(b := 1) for a, b.prop in some_iter] 中,现在允许对 b 进行赋值。请注意,按照 PEP 572 的规定,仍然不允许对推导式目标部分中存储的变量进行赋值(如 a)。(由 Nikita Sobolev 在 gh-100581 中贡献。)

  • 在类或类型的 __set_name__ 方法中引发的异常不再被 RuntimeError 包裹。上下文信息会作为 PEP 678 注释添加到异常中。(由 Irit Katriel 在 gh-77757 中贡献。)

  • try-except* 结构处理整个 ExceptionGroup 并引发另一个异常时,该异常不再被包裹在 ExceptionGroup 中。此项更改也出现在 3.11.4 版本中。(由 Irit Katriel 在 gh-103590 中贡献。)

  • 垃圾回收器现在仅在 Python 字节码评估循环的 eval 断路器机制上运行,而不是在对象分配时运行。当调用 PyErr_CheckSignals() 时,GC 也可以运行,因此需要长时间运行而不执行任何 Python 代码的 C 扩展也有机会定期执行 GC。(由 Pablo Galindo 在 gh-97922 中贡献。)

  • 所有期望布尔参数的内置函数和扩展函数现在接受任何类型的参数,而不仅仅是 boolint。(由 Serhiy Storchaka 在 gh-60203 中贡献。)

  • memoryview 现在支持半精度浮点类型(“e” 格式代码)。(由 Donghee Na 和 Antoine Pitrou 在 gh-90751 中贡献。)

  • slice 对象现在是可哈希的,允许它们用作字典键和集合项。(由 Will Bradshaw、Furkan Onder 和 Raymond Hettinger 在 gh-101264 中贡献。)

  • sum() 现在使用 Neumaier 求和来提高对浮点数或混合整数和浮点数求和时的准确性和交换性。(由 Raymond Hettinger 在 gh-100425 中贡献。)

  • 当解析包含空字节的源代码时,ast.parse() 现在会引发 SyntaxError,而不是 ValueError。(由 Pablo Galindo 在 gh-96670 中贡献。)

  • tarfile 中的提取方法和 shutil.unpack_archive() 有一个新的 *filter* 参数,允许限制可能令人惊讶或危险的 tar 功能,例如在目标目录之外创建文件。有关详细信息,请参阅 tarfile 提取过滤器。在 Python 3.14 中,默认值将切换为 'data'。(由 Petr Viktorin 在 PEP 706 中贡献。)

  • 如果底层映射是可哈希的,则 types.MappingProxyType 实例现在是可哈希的。(由 Serhiy Storchaka 在 gh-87995 中贡献。)

  • 通过新的环境变量 PYTHONPERFSUPPORT 和命令行选项 -X perf 以及新的 sys.activate_stack_trampoline()sys.deactivate_stack_trampoline()sys.is_stack_trampoline_active() 函数,添加了 对 perf profiler 的支持。(由 Pablo Galindo 设计。由 Pablo Galindo 和 Christian Heimes 贡献,并得到 Gregory P. Smith [Google] 和 Mark Shannon 在 gh-96123 中的贡献。)

新模块

  • 无。

改进的模块

array

asyncio

日历

csv

dis

  • 伪指令操作码(由编译器使用但不出现在可执行字节码中)现在在 dis 模块中公开。HAVE_ARGUMENT 仍然与实际操作码相关,但它对于伪指令没有用。请改用新的 dis.hasarg 集合。(由 Irit Katriel 在 gh-94216 中贡献。)

  • 添加了 dis.hasexc 集合,以表示设置异常处理程序的指令。(由 Irit Katriel 在 gh-94216 中贡献。)

fractions

importlib.resources

inspect

itertools

  • 添加了 itertools.batched(),用于收集到大小均匀的元组中,其中最后一个批次可能比其余的短。(由 Raymond Hettinger 在 gh-98363 中贡献。)

math

  • 添加了 math.sumprod(),用于计算乘积之和。(由 Raymond Hettinger 在 gh-100485 中贡献。)

  • 扩展了 math.nextafter() 以包括 steps 参数,用于一次向上或向下移动多个步骤。(由 Matthias Goergens、Mark Dickinson 和 Raymond Hettinger 在 gh-94906 中贡献。)

os

  • 添加了 os.PIDFD_NONBLOCK,用于在非阻塞模式下使用 os.pidfd_open() 为进程打开文件描述符。(由 Kumar Aditya 在 gh-93312 中贡献。)

  • 现在,os.DirEntry 包括 os.DirEntry.is_junction() 方法,用于检查条目是否为连接点。(由 Charles Machalow 在 gh-99547 中贡献。)

  • 在 Windows 上添加了 os.listdrives()os.listvolumes()os.listmounts() 函数,用于枚举驱动器、卷和挂载点。(由 Steve Dower 在 gh-102519 中贡献。)

  • 现在,os.stat()os.lstat() 在 Windows 上更加准确。st_birthtime 字段现在将填充文件的创建时间,并且 st_ctime 已弃用,但仍然包含创建时间(但将来将返回最后一次元数据更改,以与其他平台保持一致)。st_dev 可能最多为 64 位,st_ino 可能最多为 128 位,具体取决于您的文件系统,并且 st_rdev 始终设置为零而不是不正确的值。这两个函数在新版本的 Windows 上可能会明显更快。(由 Steve Dower 在 gh-99726 中贡献。)

os.path

pathlib

pdb

  • 添加方便的变量以临时保存调试会话的值,并提供对当前帧或返回值等值的快速访问。(由 Tian Gao 在 gh-103693 中贡献。)

random

shutil

  • shutil.make_archive() 现在将 root_dir 参数传递给支持它的自定义归档器。在这种情况下,它不再临时将进程的当前工作目录更改为 root_dir 来执行归档。(由 Serhiy Storchaka 在 gh-74696 中贡献。)

  • shutil.rmtree() 现在接受一个新参数 onexc,它是一个错误处理程序,类似于 onerror,但期望的是一个异常实例而不是 (typ, val, tb) 三元组。onerror 已被弃用。(由 Irit Katriel 在 gh-102828 中贡献。)

  • shutil.which() 现在会查询 PATHEXT 环境变量,以便在 Windows 上即使给定的 cmd 包含目录组件时,也能在 PATH 中找到匹配项。(由 Charles Machalow 在 gh-103179 中贡献。)

    shutil.which() 在 Windows 上查询可执行文件时,将调用 NeedCurrentDirectoryForExePathW,以确定当前工作目录是否应添加到搜索路径中。(由 Charles Machalow 在 gh-103179 中贡献。)

    shutil.which() 将返回一个与 cmd 匹配的路径,该路径在 Windows 上从搜索路径的其他直接匹配之前,包含来自 PATHEXT 的组件。(由 Charles Machalow 在 gh-103179 中贡献。)

sqlite3

statistics

  • 扩展 statistics.correlation(),使其包含一个 ranked 方法,用于计算排名数据的 Spearman 相关性。(由 Raymond Hettinger 在 gh-95861 中贡献。)

sys

tempfile

threading

tkinter

  • tkinter.Canvas.coords() 现在扁平化其参数。它现在不仅接受坐标作为单独的参数 (x1, y1, x2, y2, ...) 和坐标序列 ([x1, y1, x2, y2, ...]),还接受成对分组的坐标 ((x1, y1), (x2, y2), ...[(x1, y1), (x2, y2), ...]),例如 create_*() 方法。(由 Serhiy Storchaka 在 gh-94473 中贡献。)

tokenize

types

typing

  • 针对 运行时可检查协议isinstance() 检查现在使用 inspect.getattr_static() 而不是 hasattr() 来查找属性是否存在。这意味着在针对运行时可检查协议进行 isinstance() 检查期间,描述符和 __getattr__() 方法将不再被意外评估。 但是,这也可能意味着某些曾经被认为是运行时可检查协议的实例的对象可能不再被视为 Python 3.12+ 上该协议的实例,反之亦然。 大多数用户不太可能受到此更改的影响。(由 Alex Waygood 在 gh-102433 中贡献。)

  • 运行时可检查协议的成员现在在创建类后立即被视为在运行时“冻结”。将属性修补到运行时可检查协议上仍然有效,但不会影响将对象与协议进行比较的 isinstance() 检查。 例如

    >>> from typing import Protocol, runtime_checkable
    >>> @runtime_checkable
    ... class HasX(Protocol):
    ...     x = 1
    ...
    >>> class Foo: ...
    ...
    >>> f = Foo()
    >>> isinstance(f, HasX)
    False
    >>> f.x = 1
    >>> isinstance(f, HasX)
    True
    >>> HasX.y = 2
    >>> isinstance(f, HasX)  # unchanged, even though HasX now also has a "y" attribute
    True
    

    进行此更改是为了加快针对运行时可检查协议的 isinstance() 检查。

  • 针对 运行时可检查协议isinstance() 检查的性能配置文件已发生重大变化。针对只有少数成员的协议进行的 isinstance() 检查应该至少比 3.11 快 2 倍,有些可能快 20 倍或更多。 但是,针对具有多个成员的协议进行的 isinstance() 检查可能比 Python 3.11 慢。(由 Alex Waygood 在 gh-74690gh-103193 中贡献。)

  • 所有 typing.TypedDicttyping.NamedTuple 类现在都有 __orig_bases__ 属性。(由 Adrian Garcia Badaracco 在 gh-103699 中贡献。)

  • typing.dataclass_transform() 添加 frozen_default 参数。(由 Erik De Bonte 在 gh-99957 中贡献。)

unicodedata

  • Unicode 数据库已更新至 15.0.0 版。(由 Benjamin Peterson 在 gh-96734 中贡献。)

unittest

添加一个 --durations 命令行选项,显示 N 个最慢的测试用例

python3 -m unittest --durations=3 lib.tests.test_threading
.....
Slowest test durations
----------------------------------------------------------------------
1.210s     test_timeout (Lib.test.test_threading.BarrierTests)
1.003s     test_default_timeout (Lib.test.test_threading.BarrierTests)
0.518s     test_timeout (Lib.test.test_threading.EventTests)

(0.000 durations hidden.  Use -v to show these durations.)
----------------------------------------------------------------------
Ran 158 tests in 9.869s

OK (skipped=3)

(由 Giampaolo Rodola 在 gh-48330 中贡献)

uuid

优化

  • 从 Unicode 对象中删除 wstrwstr_length 成员。 这在 64 位平台上将对象大小减少了 8 或 16 个字节。 (PEP 623) (由 Inada Naoki 在 gh-92536 中贡献。)

  • 在构建过程中添加对使用 BOLT 二进制优化器的实验性支持,这可以将性能提高 1-5%。(由 Kevin Modzelewski 在 gh-90536 中贡献,并由 Donghee Na 在 gh-101525 中调整。)

  • 将正则表达式替换(函数 re.sub()re.subn() 以及相应的 re.Pattern 方法)的速度提高了 2-3 倍,针对包含组引用的替换字符串。(由 Serhiy Storchaka 在 gh-91524 中贡献。)

  • 通过延迟昂贵的字符串格式化来加速 asyncio.Task 的创建。(由 Itamar Oren 在 gh-103793 中贡献。)

  • 由于需要覆盖 PEP 701 的更改在 tokenize 模块中,tokenize.tokenize()tokenize.generate_tokens() 函数的速度提高了高达 64%。(由 Marta Gómez Macías 和 Pablo Galindo 在 gh-102856 中贡献。)

  • 通过新的 LOAD_SUPER_ATTR 指令,加速 super() 方法调用和属性加载。(由 Carl Meyer 和 Vladimir Matveev 在 gh-103497 中贡献。)

CPython 字节码更改

演示和工具

  • 移除包含旧演示脚本的 Tools/demo/ 目录。可以在 old-demos 项目中找到副本。(由 Victor Stinner 在 gh-97681 中贡献。)

  • 移除 Tools/scripts/ 目录中过时的示例脚本。可以在 old-demos 项目中找到副本。(由 Victor Stinner 在 gh-97669 中贡献。)

已弃用

Python 3.13 中待移除的内容

模块(请参阅 PEP 594

  • aifc

  • audioop

  • cgi

  • cgitb

  • chunk

  • crypt

  • imghdr

  • mailcap

  • msilib

  • nis

  • nntplib

  • ossaudiodev

  • pipes

  • sndhdr

  • spwd

  • sunau

  • telnetlib

  • uu

  • xdrlib

其他模块

API

Python 3.14 中待移除的内容

计划在 Python 3.15 中移除

  • 导入系统

    • 在未能设置 __spec__.cached 的情况下在模块上设置 __cached__ 已被弃用。 在 Python 3.15 中,导入系统或标准库将停止设置或考虑 __cached__。(gh-97879

    • 在未能设置 __spec__.parent 的情况下在模块上设置 __package__ 已被弃用。 在 Python 3.15 中,导入系统或标准库将停止设置或考虑 __package__。(gh-97879

  • ctypes:

    • 未文档化的 ctypes.SetPointerType() 函数自 Python 3.13 起已被弃用。

  • http.server:

    • 自 Python 3.13 起,过时且很少使用的 CGIHTTPRequestHandler 已被弃用。 没有直接的替代品。 任何东西都比 CGI 更好,可以将 Web 服务器与请求处理程序连接起来。

    • 自 Python 3.13 起,python -m http.server 命令行界面的 --cgi 标志已被弃用。

  • locale:

  • pathlib:

  • platform:

    • 自 Python 3.13 起,java_ver() 已被弃用。此函数仅对 Jython 支持有用,具有令人困惑的 API,并且基本上未经测试。

  • threading:

    • RLock() 在 Python 3.15 中将不接受任何参数。自 Python 3.14 起,传递任何参数都已被弃用,因为 Python 版本不允许任何参数,但 C 版本允许任何数量的位置参数或关键字参数,并忽略每个参数。

  • types:

  • typing:

    • 用于创建 NamedTuple 类的未文档化的关键字参数语法(例如 Point = NamedTuple("Point", x=int, y=int))自 Python 3.13 起已被弃用。请改用基于类的语法或函数式语法。

    • 自 Python 3.13 起,typing.no_type_check_decorator() 装饰器函数已被弃用。在 typing 模块中存在八年后,它仍然未被任何主要的类型检查器支持。

  • wave:

计划在 Python 3.16 中移除

  • 导入系统

    • 在未能设置 __spec__.loader 的同时设置模块的 __loader__ 已被弃用。在 Python 3.16 中,导入系统或标准库将不再设置或考虑 __loader__

  • array:

    • 自 Python 3.3 起,文档中已弃用 'u' 格式代码 (wchar_t),自 Python 3.13 起,运行时已弃用。请改用 'w' 格式代码 (Py_UCS4) 来表示 Unicode 字符。

  • asyncio:

  • builtins:

    • 对布尔类型进行按位反转,例如 ~True~False,自 Python 3.12 起已被弃用,因为它会产生令人惊讶且不直观的结果(-2-1)。对于布尔值的逻辑非,请改用 not x。在极少数情况下,如果您需要底层整数的按位反转,请显式转换为 int (~int(x))。

  • shutil:

    • 自 Python 3.14 起,ExecError 异常已被弃用。自 Python 3.4 以来,shutil 中的任何函数都没有使用它,现在它是 RuntimeError 的别名。

  • symtable:

  • sys:

  • tarfile:

    • 自 Python 3.13 起,未文档化且未使用的 TarFile.tarfile 属性已被弃用。

计划在未来版本中移除

以下 API 将在未来删除,但目前尚未安排删除日期。

  • argparse:嵌套参数组和嵌套互斥组已被弃用。

  • array'u' 格式代码 (gh-57281)

  • builtins:

    • bool(NotImplemented).

    • 生成器: throw(type, exc, tb)athrow(type, exc, tb) 签名已弃用:请改用 throw(exc)athrow(exc),即单参数签名。

    • 目前,Python 允许数字字面量紧跟关键字,例如 0in x1or x0if 1else 2。这允许出现令人困惑和模棱两可的表达式,如 [0x1for x in y] (可以解释为 [0x1 for x in y][0x1f or x in y])。如果数字字面量紧跟以下关键字之一,则会引发语法警告:andelseforifinisor。在未来的版本中,这将改为语法错误。(gh-87999

    • 支持 __index__()__int__() 方法返回非 int 类型:这些方法将需要返回 int 的严格子类的实例。

    • 支持 __float__() 方法返回 float 的严格子类:这些方法将需要返回 float 的实例。

    • 支持 __complex__() 方法返回 complex 的严格子类:这些方法将需要返回 complex 的实例。

    • int() 的调用委托给 __trunc__() 方法。

    • 现在不建议将复数作为 complex() 构造函数中的 *real* 或 *imag* 参数传递;它应该只作为单个位置参数传递。(由 Serhiy Storchaka 在 gh-109218 中贡献。)

  • calendarcalendar.Januarycalendar.February 常量已弃用,并由 calendar.JANUARYcalendar.FEBRUARY 替代。(由 Prince Roshan 在 gh-103636 中贡献。)

  • codeobject.co_lnotab:请使用 codeobject.co_lines() 方法代替。

  • datetime:

    • utcnow():请使用 datetime.datetime.now(tz=datetime.UTC)

    • utcfromtimestamp():请使用 datetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC)

  • gettext:复数形式的值必须是整数。

  • importlib:

    • load_module() 方法:请使用 exec_module() 代替。

    • cache_from_source() 的 *debug_override* 参数已弃用:请使用 *optimization* 参数代替。

  • importlib.metadata:

    • EntryPoints 元组接口。

    • 返回值上的隐式 None

  • loggingwarn() 方法自 Python 3.3 起已被弃用,请使用 warning() 代替。

  • mailbox:不推荐使用 StringIO 输入和文本模式,请使用 BytesIO 和二进制模式代替。

  • os:在多线程进程中调用 os.register_at_fork()

  • pydoc.ErrorDuringImport:*exc_info* 参数的元组值已弃用,请使用异常实例。

  • re:正则表达式中的数字组引用和组名现在应用更严格的规则。现在只接受 ASCII 数字序列作为数字引用。字节模式和替换字符串中的组名现在只能包含 ASCII 字母、数字和下划线。(由 Serhiy Storchaka 在 gh-91760 中贡献。)

  • sre_compilesre_constantssre_parse 模块。

  • shutilrmtree() 的 *onerror* 参数在 Python 3.12 中已弃用;请使用 *onexc* 参数代替。

  • ssl 选项和协议

    • 不带 protocol 参数的 ssl.SSLContext 已弃用。

    • ssl.SSLContextset_npn_protocols()selected_npn_protocol() 已弃用:请使用 ALPN 代替。

    • ssl.OP_NO_SSL* 选项

    • ssl.OP_NO_TLS* 选项

    • ssl.PROTOCOL_SSLv3

    • ssl.PROTOCOL_TLS

    • ssl.PROTOCOL_TLSv1

    • ssl.PROTOCOL_TLSv1_1

    • ssl.PROTOCOL_TLSv1_2

    • ssl.TLSVersion.SSLv3

    • ssl.TLSVersion.TLSv1

    • ssl.TLSVersion.TLSv1_1

  • sysconfig.is_python_build() 的 *check_home* 参数已弃用并被忽略。

  • threading 方法

  • typing.Text (gh-92332)。

  • unittest.IsolatedAsyncioTestCase:从测试用例返回值(不是 None)已弃用。

  • urllib.parse 中已弃用的函数:请使用 urlparse() 代替。

    • splitattr()

    • splithost()

    • splitnport()

    • splitpasswd()

    • splitport()

    • splitquery()

    • splittag()

    • splittype()

    • splituser()

    • splitvalue()

    • to_bytes()

  • urllib.request:调用请求的 URLopenerFancyURLopener 样式已被弃用。请使用较新的 urlopen() 函数和方法。

  • wsgirefSimpleHandler.stdout.write() 不应进行部分写入。

  • xml.etree.ElementTree:测试 Element 的真值已被弃用。在未来的版本中,它将始终返回 True。请首选显式的 len(elem)elem is not None 测试。

  • zipimport.zipimporter.load_module() 已被弃用:请改用 exec_module()

已移除

asynchat 和 asyncore

  • 这两个模块已按照 PEP 594 中的时间表移除,它们在 Python 3.6 中已被弃用。请改用 asyncio。(由 Nikita Sobolev 在 gh-96580 中贡献。)

configparser

distutils

  • 移除 distutils 包。它在 Python 3.10 中被 PEP 632 “弃用 distutils 模块”弃用。对于仍在使用 distutils 且无法更新为其他内容的项目,可以安装 setuptools 项目:它仍然提供 distutils。(由 Victor Stinner 在 gh-92584 中贡献。)

ensurepip

  • ensurepip 中删除捆绑的 setuptools wheel,并停止在由 venv 创建的环境中安装 setuptools。

    pip (>= 22.1) 不需要在环境中安装 setuptools。setuptools 基(和 distutils 基)的包仍然可以与 pip install 一起使用,因为 pip 将在其用于构建包的构建环境中提供 setuptools

    easy_installpkg_resourcessetuptoolsdistutils 不再默认在由 venv 创建或由 ensurepip 引导的环境中提供,因为它们是 setuptools 包的一部分。对于在运行时依赖这些的项目,应将 setuptools 项目声明为依赖项并单独安装(通常使用 pip)。

    (由 Pradyun Gedam 在 gh-95299 中贡献。)

enum

  • 移除 enumEnumMeta.__getattr__,枚举属性访问不再需要它。(由 Ethan Furman 在 gh-95083 中贡献。)

ftplib

  • 移除 ftplibFTP_TLS.ssl_version 类属性:请改用 *context* 参数。(由 Victor Stinner 在 gh-94172 中贡献。)

gzip

  • 移除 gzipgzip.GzipFilefilename 属性,该属性自 Python 2.6 起已被弃用,请改用 name 属性。在写入模式下,如果不存在,filename 属性会添加 '.gz' 文件扩展名。(由 Victor Stinner 在 gh-94196 中贡献。)

hashlib

  • 移除 hashlibhashlib.pbkdf2_hmac() 的纯 Python 实现,该实现在 Python 3.10 中已被弃用。Python 3.10 及更高版本需要 OpenSSL 1.1.1 (PEP 644):此 OpenSSL 版本提供了 pbkdf2_hmac() 的 C 实现,速度更快。(由 Victor Stinner 在 gh-94199 中贡献。)

importlib

  • 现在已完成 importlib 中许多先前已弃用的清理工作

    • 已移除对 module_repr() 的引用和支持。(由 Barry Warsaw 在 gh-97850 中贡献。)

    • importlib.util.set_packageimportlib.util.set_loaderimportlib.util.module_for_loader 已全部移除。(由 Brett Cannon 和 Nikita Sobolev 在 gh-65961gh-97850 中贡献。)

    • 已移除对 find_loader()find_module() API 的支持。(由 Barry Warsaw 在 gh-98040 中贡献。)

    • importlib.abc.Finderpkgutil.ImpImporterpkgutil.ImpLoader 已被移除。(由 Barry Warsaw 在 gh-98040 中贡献。)

imp

  • imp 模块已被移除。(由 Barry Warsaw 在 gh-98040 中贡献。)

    要进行迁移,请查阅以下对应表

    imp

    importlib

    imp.NullImporter

    None 插入到 sys.path_importer_cache

    imp.cache_from_source()

    importlib.util.cache_from_source()

    imp.find_module()

    importlib.util.find_spec()

    imp.get_magic()

    importlib.util.MAGIC_NUMBER

    imp.get_suffixes()

    importlib.machinery.SOURCE_SUFFIXESimportlib.machinery.EXTENSION_SUFFIXESimportlib.machinery.BYTECODE_SUFFIXES

    imp.get_tag()

    sys.implementation.cache_tag

    imp.load_module()

    importlib.import_module()

    imp.new_module(name)

    types.ModuleType(name)

    imp.reload()

    importlib.reload()

    imp.source_from_cache()

    importlib.util.source_from_cache()

    imp.load_source()

    见下文

    imp.load_source() 替换为

    import importlib.util
    import importlib.machinery
    
    def load_source(modname, filename):
        loader = importlib.machinery.SourceFileLoader(modname, filename)
        spec = importlib.util.spec_from_file_location(modname, filename, loader=loader)
        module = importlib.util.module_from_spec(spec)
        # The module is always executed and not cached in sys.modules.
        # Uncomment the following line to cache the module.
        # sys.modules[module.__name__] = module
        loader.exec_module(module)
        return module
    
  • 移除没有替代的 imp 函数和属性

    • 未文档化的函数

      • imp.init_builtin()

      • imp.load_compiled()

      • imp.load_dynamic()

      • imp.load_package()

    • imp.lock_held()imp.acquire_lock()imp.release_lock():Python 3.3 中锁定方案已更改为每个模块锁定。

    • imp.find_module() 常量:SEARCH_ERRORPY_SOURCEPY_COMPILEDC_EXTENSIONPY_RESOURCEPKG_DIRECTORYC_BUILTINPY_FROZENPY_CODERESOURCEIMP_HOOK

io

  • 移除 ioio.OpenWrapper_pyio.OpenWrapper,它们在 Python 3.10 中已弃用:直接使用 open() 即可。open()io.open())函数是一个内置函数。从 Python 3.10 开始,_pyio.open() 也是一个静态方法。(由 Victor Stinner 在 gh-94169 中贡献。)

locale

smtpd

  • 根据 PEP 594 中的计划,smtpd 模块已被移除,它在 Python 3.4.7 和 3.5.4 中已弃用。请改用 aiosmtpd PyPI 模块或任何其他基于 asyncio 的服务器。(由 Oleg Iarygin 在 gh-93243 中贡献。)

sqlite3

  • 以下未文档化的 sqlite3 功能在 Python 3.10 中已弃用,现在已被删除

    • sqlite3.enable_shared_cache()

    • sqlite3.OptimizedUnicode

    如果必须使用共享缓存,请使用 cache=shared 查询参数以 URI 模式打开数据库。

    自 Python 3.3 以来,sqlite3.OptimizedUnicode 文本工厂一直是 str 的别名。先前将文本工厂设置为 OptimizedUnicode 的代码可以显式使用 str,或者依赖于默认值,该值也是 str

    (由 Erlend E. Aasland 在 gh-92548 中贡献。)

ssl

  • 移除 sslssl.RAND_pseudo_bytes() 函数,它在 Python 3.6 中已弃用:请改用 os.urandom()ssl.RAND_bytes()。(由 Victor Stinner 在 gh-94199 中贡献。)

  • 移除 ssl.match_hostname() 函数。它在 Python 3.7 中已弃用。自 Python 3.7 以来,OpenSSL 执行主机名匹配,Python 不再使用 ssl.match_hostname() 函数。(由 Victor Stinner 在 gh-94199 中贡献。)

  • 移除 ssl.wrap_socket() 函数,它在 Python 3.7 中已弃用:请改为创建一个 ssl.SSLContext 对象并调用其 ssl.SSLContext.wrap_socket 方法。任何仍然使用 ssl.wrap_socket() 的软件包都是损坏且不安全的。该函数既不发送 SNI TLS 扩展,也不验证服务器主机名。代码容易受到 CWE 295 (不正确的证书验证)的影响。(由 Victor Stinner 在 gh-94199 中贡献。)

unittest

webbrowser

  • webbrowser 中移除对过时浏览器的支持。移除的浏览器包括:Grail、Mosaic、Netscape、Galeon、Skipstone、Iceape、Firebird 和 35 及以下版本的 Firefox ( gh-102871 )。

xml.etree.ElementTree

  • 移除纯 Python 实现的 ElementTree.Element.copy() 方法,该方法在 Python 3.10 中已弃用,请改用 copy.copy() 函数。xml.etree.ElementTree 的 C 实现没有 copy() 方法,只有一个 __copy__() 方法。(由 Victor Stinner 在 gh-94383 中贡献。)

zipimport

  • 移除 zipimportfind_loader()find_module() 方法,这两个方法在 Python 3.10 中已弃用:请改用 find_spec() 方法。有关原理,请参阅 PEP 451。(由 Victor Stinner 在 gh-94379 中贡献。)

其他

  • 从文档 MakefileDoc/tools/rstlint.py 中删除 suspicious 规则,这两个文件都支持 sphinx-lint。(由 Julien Palard 在 gh-98179 中贡献。)

  • ftplibimaplibpoplibsmtplib 模块中移除 keyfilecertfile 参数,以及从 http.client 模块中移除 key_filecert_filecheck_hostname 参数,这些参数自 Python 3.6 起已弃用。请改用 context 参数(imaplib 中的 ssl_context)。(由 Victor Stinner 在 gh-94172 中贡献。)

  • 从多个 stdlib 模块和测试中删除 Jython 兼容性 hack。(由 Nikita Sobolev 在 gh-99482 中贡献。)

  • ctypes 模块中移除 _use_broken_old_ctypes_structure_semantics_ 标志。(由 Nikita Sobolev 在 gh-99285 中贡献。)

移植到 Python 3.12

本节列出了先前描述的更改和其他错误修复,这些更改可能需要您修改代码。

Python API 中的更改

  • 现在对正则表达式中的数字组引用和组名称应用了更严格的规则。现在只接受 ASCII 数字序列作为数字引用。字节模式和替换字符串中的组名称现在只能包含 ASCII 字母和数字以及下划线。(由 Serhiy Storchaka 在 gh-91760 中贡献。)

  • 移除自 Python 3.10 起已弃用的 randrange() 功能。以前,randrange(10.0) 会无损地转换为 randrange(10)。现在,它会引发 TypeError。此外,对于非整数值(例如 randrange(10.5)randrange('10'))引发的异常已从 ValueError 更改为 TypeError。这也防止了 randrange(1e25) 会静默地从比 randrange(10**25) 更大的范围中进行选择的错误。(最初由 Serhiy Storchaka 建议 gh-86388。)

  • argparse.ArgumentParser 更改了从文件读取参数(例如 fromfile_prefix_chars 选项)的编码和错误处理程序,从默认文本编码(例如 locale.getpreferredencoding(False))更改为 文件系统编码和错误处理程序。在 Windows 上,参数文件应使用 UTF-8 而不是 ANSI 代码页进行编码。

  • 移除在 Python 3.4.7 和 3.5.4 中已弃用的基于 asyncoresmtpd 模块。推荐的替代方案是基于 asyncioaiosmtpd PyPI 模块。

  • shlex.split():为 s 参数传递 None 现在会引发异常,而不是读取 sys.stdin。该功能在 Python 3.9 中已弃用。(由 Victor Stinner 在 gh-94352 中贡献。)

  • os 模块不再接受类似字节的路径,例如 bytearraymemoryview 类型:对于字节字符串,仅接受精确的 bytes 类型。(由 Victor Stinner 在 gh-98393 中贡献。)

  • 如果子解释器中使用 syslog.openlog()syslog.closelog(),现在会失败。 syslog.syslog() 仍然可以在子解释器中使用,但前提是必须在主解释器中先调用过 syslog.openlog()。 这些新的限制不适用于主解释器,因此只有极少数用户可能会受到影响。 此更改有助于解释器隔离。 此外,syslog 是对进程全局资源的包装,最好从主解释器进行管理。(由 Donghee Na 在 gh-99127 中贡献。)

  • cached_property() 未记录的锁定行为已被移除,因为它会跨类的所有实例进行锁定,导致高锁争用。 这意味着,如果两个线程竞争,则缓存属性的 getter 函数现在可能会为单个实例运行多次。 对于大多数简单的缓存属性(例如,那些是幂等且仅根据实例的其他属性计算值的属性),这不会有问题。 如果需要同步,请在缓存属性的 getter 函数中或在多线程访问点周围实现锁定。

  • sys._current_exceptions() 现在返回一个从线程 ID 到异常实例的映射,而不是到一个 (typ, exc, tb) 元组。(由 Irit Katriel 在 gh-103176 中贡献。)

  • 当使用 tarfileshutil.unpack_archive() 解压缩 tar 文件时,请传递 filter 参数以限制可能令人意外或危险的功能。 有关详细信息,请参阅 提取过滤器

  • 由于 PEP 701 中引入的更改,tokenize.tokenize()tokenize.generate_tokens() 函数的输出现在已更改。 这意味着,不再为 f 字符串发出 STRING 标记,而是会生成 PEP 701 中描述的标记:除了表达式组件中标记化的相应标记外,现在还会为 f 字符串的“字符串”部分发出 FSTRING_STARTFSTRING_MIDDLEFSTRING_END。 例如,对于 f 字符串 f"start {1+1} end",旧版本的标记器发出

    1,0-1,18:           STRING         'f"start {1+1} end"'
    

    而新版本发出

    1,0-1,2:            FSTRING_START  'f"'
    1,2-1,8:            FSTRING_MIDDLE 'start '
    1,8-1,9:            OP             '{'
    1,9-1,10:           NUMBER         '1'
    1,10-1,11:          OP             '+'
    1,11-1,12:          NUMBER         '1'
    1,12-1,13:          OP             '}'
    1,13-1,17:          FSTRING_MIDDLE ' end'
    1,17-1,18:          FSTRING_END    '"'
    

    此外,由于支持 PEP 701 所需的更改,可能还会出现一些细微的行为更改。 其中一些更改包括

    • 当标记化某些无效的 Python 字符(如 !)时,发出的标记的 type 属性已从 ERRORTOKEN 更改为 OP

    • 不完整的单行字符串现在也会像不完整的多行字符串一样引发 tokenize.TokenError

    • 某些不完整或无效的 Python 代码现在在标记化时会引发 tokenize.TokenError,而不是返回任意的 ERRORTOKEN 标记。

    • 不再支持在同一文件中混合使用制表符和空格作为缩进,并且会引发 TabError

  • threading 模块现在期望 _thread 模块具有 _is_main_interpreter 属性。 它是一个没有参数的函数,如果当前解释器是主解释器,则返回 True

    任何提供自定义 _thread 模块的库或应用程序都应提供 _is_main_interpreter()。(请参阅 gh-112826。)

构建更改

  • Python 不再使用 setup.py 来构建共享的 C 扩展模块。 构建参数(如头文件和库)在 configure 脚本中检测。 扩展由 Makefile 构建。 大多数扩展使用 pkg-config,并回退到手动检测。(由 Christian Heimes 在 gh-93939 中贡献。)

  • 现在需要使用两个参数的 va_start()(如 va_start(args, format))来构建 Python。 不再使用单个参数调用 va_start()。(由 Kumar Aditya 在 gh-93207 中贡献。)

  • 如果 Clang 编译器接受该标志,CPython 现在默认使用 ThinLTO 选项作为链接时优化策略。(由 Donghee Na 在 gh-89536 中贡献。)

  • Makefile 中添加 COMPILEALL_OPTS 变量以覆盖 compileall 选项(默认值:-j0),用于 make install。 还将 3 个 compileall 命令合并为一个命令,以一次为所有优化级别(0、1、2)构建 .pyc 文件。(由 Victor Stinner 在 gh-99289 中贡献。)

  • 为 64 位 LoongArch 添加平台三元组

    • loongarch64-linux-gnusf

    • loongarch64-linux-gnuf32

    • loongarch64-linux-gnu

    (由 Zhang Na 在 gh-90656 中贡献。)

  • PYTHON_FOR_REGEN 现在需要 Python 3.10 或更高版本。

  • 现在需要 Autoconf 2.71 和 aclocal 1.16.4 来重新生成 !configure。(由 Christian Heimes 在 gh-89886 中贡献。)

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

C API 更改

新功能

  • PEP 683:引入不朽对象,允许对象绕过引用计数,以及 C-API 的相关更改

    • _Py_IMMORTAL_REFCNT:定义对象为不朽的引用计数。

      为不朽。

    • _Py_IsImmortal 检查对象是否具有不朽的引用计数。

    • PyObject_HEAD_INIT 现在会将引用计数初始化为

      _Py_IMMORTAL_REFCNT 当与 Py_BUILD_CORE 一起使用时。

    • SSTATE_INTERNED_IMMORTAL 不朽的 interned unicode 对象的标识符。

      是不朽的。

    • SSTATE_INTERNED_IMMORTAL_STATIC 不朽且静态的 interned unicode 对象的标识符

      是静态的

    • sys.getunicodeinternedsize 这将返回已 interned 的 unicode 对象总数。

      现在需要这样做,以便 refleak.py 正确跟踪引用计数和已分配的块

    (由 Eddie Elizondo 在 gh-84436 中贡献。)

  • PEP 684:添加了新的 Py_NewInterpreterFromConfig() 函数和 PyInterpreterConfig,它们可用于创建具有自己的 GIL 的子解释器。(有关更多信息,请参阅 PEP 684:每个解释器 GIL。)(由 Eric Snow 在 gh-104110 中贡献。)

  • 在有限 C API 版本 3.12 中, Py_INCREF()Py_DECREF() 函数现在实现为不透明的函数调用,以隐藏实现细节。(由 Victor Stinner 在 gh-105387 中贡献。)

移植到 Python 3.12

  • 已删除基于 Py_UNICODE* 表示的旧版 Unicode API。请迁移到基于 UTF-8 或 wchar_t* 的 API。

  • PyArg_ParseTuple() 这样的参数解析函数不再支持基于 Py_UNICODE* 的格式(例如 u, Z)。请迁移到其他 Unicode 格式,如 szesU

  • 所有静态内置类型的 tp_weaklist 始终为 NULL。这是 PyTypeObject 上的一个内部字段,但我们在此指出此更改,以防有人直接访问该字段。为了避免破坏,请考虑使用现有的公共 C-API,或者在必要时使用(仅限内部的)_PyObject_GET_WEAKREFS_LISTPTR() 宏。

  • 这个仅限内部的 PyTypeObject.tp_subclasses 现在可能不再是有效的对象指针。它的类型已更改为 void* 以反映这一点。我们在此说明此更改,以防有人直接访问此仅限内部的字段。

    要获取子类列表,请调用 Python 方法 __subclasses__() (例如,使用 PyObject_CallMethod())。

  • PyUnicode_FromFormat()PyUnicode_FromFormatV() 中添加了对更多格式化选项的支持(左对齐、八进制、大写十六进制、intmax_tptrdiff_twchar_t C 字符串、可变宽度和精度)。(由 Serhiy Storchaka 在 gh-98836 中贡献。)

  • PyUnicode_FromFormat()PyUnicode_FromFormatV() 中无法识别的格式字符现在会设置 SystemError。在以前的版本中,它会导致格式字符串的其余部分按原样复制到结果字符串,并丢弃任何额外的参数。(由 Serhiy Storchaka 在 gh-95781 中贡献。)

  • 修复了 PyUnicode_FromFormat()PyUnicode_FromFormatV() 中错误的符号位置。(由 Philip Georgi 在 gh-95504 中贡献。)

  • 想要添加 __dict__ 或弱引用槽的扩展类应分别使用 Py_TPFLAGS_MANAGED_DICTPy_TPFLAGS_MANAGED_WEAKREF,而不是 tp_dictoffsettp_weaklistoffset。仍然支持使用 tp_dictoffsettp_weaklistoffset,但它并不完全支持多重继承 (gh-95589),并且性能可能会更差。声明了 Py_TPFLAGS_MANAGED_DICT 的类必须调用 _PyObject_VisitManagedDict()_PyObject_ClearManagedDict() 来遍历和清除其实例的字典。要清除弱引用,请像以前一样调用 PyObject_ClearWeakRefs()

  • PyUnicode_FSDecoder() 函数不再接受类似字节的路径,如 bytearraymemoryview 类型:对于字节字符串,只接受精确的 bytes 类型。(由 Victor Stinner 在 gh-98393 中贡献。)

  • Py_CLEARPy_SETREFPy_XSETREF 宏现在只计算它们的参数一次。如果参数有副作用,这些副作用将不再重复。(由 Victor Stinner 在 gh-98724 中贡献。)

  • 解释器的错误指示器现在始终被规范化。这意味着 PyErr_SetObject()PyErr_SetString() 和其他设置错误指示器的函数现在会在存储异常之前将其规范化。(由 Mark Shannon 在 gh-101578 中贡献。)

  • _Py_RefTotal 不再是权威性的,只是为了 ABI 兼容性而保留。请注意,它是一个内部全局变量,仅在调试版本中可用。如果您碰巧正在使用它,那么您需要开始使用 _Py_GetGlobalRefTotal()

  • 以下函数现在为新创建的类型选择适当的元类:

    创建其元类覆盖了 tp_new 的类已弃用,并且在 Python 3.14+ 中将被禁止。请注意,这些函数会忽略元类的 tp_new,可能会允许不完整的初始化。

    请注意,PyType_FromMetaclass()(在 Python 3.12 中添加)已经禁止创建其元类覆盖了 tp_new 的类(Python 中的 __new__())。

    由于 tp_new 覆盖了 PyType_From* 函数所做的几乎所有事情,因此两者互不兼容。现有行为(在类型创建的几个步骤中忽略元类)通常是不安全的,因为(元)类假设已调用 tp_new。没有简单的通用解决方法。以下方法之一可能对您有效:

    • 如果您控制元类,请避免在其中使用 tp_new

      • 如果可以跳过初始化,则可以在 tp_init 中完成初始化。

      • 如果不需要从 Python 实例化元类,请使用 Py_TPFLAGS_DISALLOW_INSTANTIATION 标志将其 tp_new 设置为 NULL。这使得 PyType_From* 函数可以接受它。

    • 避免使用 PyType_From* 函数:如果您不需要 C 特有的功能(槽或设置实例大小),请通过 调用 元类来创建类型。

    • 如果您知道可以安全地跳过 tp_new,请使用 Python 中的 warnings.catch_warnings() 过滤掉弃用警告。

  • PyOS_InputHookPyOS_ReadlineFunctionPointer 不再在子解释器中调用。这是因为客户端通常依赖于进程范围的全局状态(因为这些回调无法恢复扩展模块状态)。

    这也避免了扩展可能发现自己在不支持(或尚未加载)的子解释器中运行的情况。有关更多信息,请参阅 gh-104668

  • PyLongObject 的内部结构已更改,以获得更好的性能。尽管 PyLongObject 的内部结构是私有的,但一些扩展模块会使用它们。不应再直接访问内部字段,而应使用以 PyLong_... 开头的 API 函数。提供了两个新的*不稳定*API 函数,用于高效访问适合单个机器字的 PyLongObject 的值:

  • 现在,无论内存域如何,通过 PyMem_SetAllocator() 设置的自定义分配器都必须是线程安全的。 那些没有自身状态的分配器(包括“钩子”)不受影响。 如果你的自定义分配器还不是线程安全的,并且需要指导,请创建一个新的 GitHub issue 并抄送 @ericsnowcurrently

已弃用

Python 3.14 中待移除

Python 3.15 中待移除

未来版本中待移除项

以下 API 已被弃用,将被移除,尽管目前尚未安排移除的日期。

已移除项

  • 移除 token.h 头文件。从来没有任何公共的词法分析器 C API。token.h 头文件仅供 Python 内部使用。(由 Victor Stinner 在 gh-92651 中贡献。)

  • 已移除旧版的 Unicode API。 请参阅 PEP 623 了解详情。

    • PyUnicode_WCHAR_KIND

    • PyUnicode_AS_UNICODE()

    • PyUnicode_AsUnicode()

    • PyUnicode_AsUnicodeAndSize()

    • PyUnicode_AS_DATA()

    • PyUnicode_FromUnicode()

    • PyUnicode_GET_SIZE()

    • PyUnicode_GetSize()

    • PyUnicode_GET_DATA_SIZE()

  • 移除 PyUnicode_InternImmortal() 函数宏。(由 Victor Stinner 在 gh-85858 中贡献。)