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-strings 已删除了许多限制,“你的意思是……”建议也持续改进。新的类型参数语法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-string 的句法形式化

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

  • 引号重用:在 Python 3.11 中,重用与包含 f-string 相同的引号会引发 SyntaxError,强制用户使用其他可用引号(例如,如果 f-string 使用单引号,则使用双引号或三引号)。在 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-string 的嵌套方式没有明确限制,但字符串引号不能在 f-string 的表达式组件内重用这一事实使得任意嵌套 f-string 变得不可能。实际上,这是可以编写的最深层嵌套的 f-string

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

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

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

    >>> 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-string 表达式不能包含任何 \ 字符。这也影响了 Unicode 转义序列(例如 \N{snowman}),因为这些序列包含以前不能成为 f-string 表达式组件一部分的 \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-strings),现在 f-string 的错误消息更精确,并包含错误的精确位置。例如,在 Python 3.11 中,以下 f-string 会引发 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-strings 是用 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 提供,尽管 预计 3.13 将提供 Python API

使用新的 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 抽象基类提供了一种表示缓冲区对象的标准方式,例如在类型注释中。新的 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 xSyntaxError 错误消息。(由 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 中贡献。)

  • 在 Python 3.11 中已弃用的大于 0o377 的八进制转义(例如:"\477"),现在会生成 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 字节码评估循环的评估断路器机制上运行,而不是对象分配。GC 也可以在调用 PyErr_CheckSignals() 时运行,因此需要长时间运行而无需执行任何 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 分析器的支持。(由 Pablo Galindo 设计。由 Pablo Galindo 和 Christian Heimes 贡献,并得到 Gregory P. Smith [Google] 和 Mark Shannon 在 gh-96123 中的贡献。)

新模块

  • 无。

改进的模块

array

asyncio

  • asyncio 中写入套接字的性能显著提高。asyncio 现在在写入套接字时避免不必要的复制,如果平台支持,则使用 sendmsg()。(由 Kumar Aditya 在 gh-91166 中贡献。)

  • 添加 asyncio.eager_task_factory()asyncio.create_eager_task_factory() 函数,以允许事件循环选择启用渴望任务执行,从而使某些用例速度提高 2 到 5 倍。(由 Jacob Bower & Itamar Oren 在 gh-102853gh-104140gh-104138 中贡献)

  • 在 Linux 上,如果 os.pidfd_open() 可用且功能正常,asyncio 默认使用 asyncio.PidfdChildWatcher,而不是 asyncio.ThreadedChildWatcher。(由 Kumar Aditya 在 gh-98024 中贡献。)

  • 事件循环现在为每个平台使用最佳可用的子观察者(如果支持则为 asyncio.PidfdChildWatcher,否则为 asyncio.ThreadedChildWatcher),因此不建议手动配置子观察者。(由 Kumar Aditya 在 gh-94597 中贡献。)

  • asyncio.run() 添加 loop_factory 参数,允许指定自定义事件循环工厂。(由 Kumar Aditya 在 gh-99388 中贡献。)

  • 添加 asyncio.current_task() 的 C 实现,速度提高了 4-6 倍。(由 Itamar Oren 和 Pranav Thulasiram Bhat 在 gh-100344 中贡献。)

  • asyncio.iscoroutine() 现在对生成器返回 False,因为 asyncio 不支持旧的基于生成器的协程。(由 Kumar Aditya 在 gh-102748 中贡献。)

  • asyncio.wait()asyncio.as_completed() 现在接受生成任务的生成器。(由 Kumar Aditya 在 gh-78530 中贡献。)

calendar

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

platform

  • 增加对检测 Windows 11 和 Windows Server 2012 以后版本的支持。此前,在 Windows Server 2012 以后和 Windows 11 上的查询会返回 Windows-10。(由 Steve Dower 在 gh-89545 中贡献。)

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 环境变量,即使给定的 cmd 包含目录组件,也会在 Windows 上的 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()runtime-checkable protocols 的检查现在使用 inspect.getattr_static() 而不是 hasattr() 来查找属性是否存在。这意味着描述符和 __getattr__() 方法在对可运行时检查协议进行 isinstance() 检查时不再意外求值。然而,这也可能意味着一些过去被认为是可运行时检查协议实例的对象,在 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() 检查。

  • runtime-checkable protocolsisinstance() 检查的性能配置文件已显著改变。大多数对只有少数成员的协议的 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 贡献)。

  • 作为 tokenize 模块中覆盖 PEP 701 所需更改的副作用,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 中移除

  • argparseargparse.BooleanOptionalActiontypechoicesmetavar 参数已弃用,并将在 3.14 中移除。(由 Nikita Sobolev 在 gh-92248 贡献)。

  • ast:以下功能自 Python 3.8 起已在文档中弃用,现在在运行时访问或使用时会发出 DeprecationWarning,并将在 Python 3.14 中移除:

    • ast.Num

    • ast.Str

    • ast.Bytes

    • ast.NameConstant

    • ast.Ellipsis

    请改用 ast.Constant。(由 Serhiy Storchaka 在 gh-90953 贡献)。

  • asyncio:

    • 子进程观察器类 asyncio.MultiLoopChildWatcherasyncio.FastChildWatcherasyncio.AbstractChildWatcherasyncio.SafeChildWatcher 已弃用,并将在 Python 3.14 中移除。(由 Kumar Aditya 在 gh-94597 贡献)。

    • asyncio.set_child_watcher()asyncio.get_child_watcher()asyncio.AbstractEventLoopPolicy.set_child_watcher()asyncio.AbstractEventLoopPolicy.get_child_watcher() 已弃用,并将在 Python 3.14 中移除。(由 Kumar Aditya 在 gh-94597 贡献)。

    • 如果未设置当前事件循环,并且默认事件循环策略的 get_event_loop() 方法决定创建一个事件循环,它现在会发出 DeprecationWarning。(由 Serhiy Storchaka 和 Guido van Rossum 在 gh-100160 贡献)。

  • emailemail.utils.localtime() 中的 isdst 参数已弃用。(由 Alan Williams 在 gh-72346 贡献)。

  • importlib.abc 弃用类

    • importlib.abc.ResourceReader

    • importlib.abc.Traversable

    • importlib.abc.TraversableResources

    请改用 importlib.resources.abc 类:

    (由 Jason R. Coombs 和 Hugo van Kemenade 在 gh-93963 中贡献。)

  • itertools 对复制、深复制和 pickle 操作的支持未文档化、效率低下、历史上存在 bug 且不一致。这将从 3.14 中移除,以显著减少代码量和维护负担。(由 Raymond Hettinger 在 gh-101588 贡献)。

  • multiprocessing:在 Linux、BSD 和其他非 macOS POSIX 平台上(目前默认为 'fork'),默认启动方法将更改为更安全的方法 (gh-84559)。添加运行时警告被认为过于具有破坏性,因为大多数代码预计不会关心。使用 get_context()set_start_method() API 显式指定您的代码何时 *需要* 'fork'。请参阅 上下文和启动方法

  • pathlibis_relative_to()relative_to():传递额外参数已弃用。

  • pkgutilpkgutil.find_loader()pkgutil.get_loader() 现在会引发 DeprecationWarning;请改用 importlib.util.find_spec()。(由 Nikita Sobolev 在 gh-97850 贡献)。

  • pty:

  • sqlite3:

  • urlliburllib.parse.Quoter 已弃用:它无意作为公共 API。(由 Gregory P. Smith 在 gh-88168 贡献)。

计划在 Python 3.15 中移除

  • 导入系统

    • 在设置模块的 __cached__ 属性时,若未同时设置 __spec__.cached,此行为已被弃用。在 Python 3.15 中,导入系统或标准库将不再设置或考虑 __cached__ 属性。(由 gh-97879 贡献)

    • 在设置模块的 __package__ 属性时,若未同时设置 __spec__.parent,此行为已被弃用。在 Python 3.15 中,导入系统或标准库将不再设置或考虑 __package__ 属性。(由 gh-97879 贡献)

  • ctypes:

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

  • http.server:

    • 过时且很少使用的 CGIHTTPRequestHandler 已从 Python 3.13 开始弃用。没有直接的替代品。任何将 Web 服务器与请求处理程序对接的方式都比 CGI 好。

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

  • importlib:

    • load_module() 方法:请改用 exec_module()

  • locale:

  • pathlib:

  • platform:

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

  • sysconfig:

  • threading:

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

  • types:

  • typing:

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

    • 使用 TypedDict 的函数式语法时,未向 fields 参数传递值(TD = TypedDict("TD"))或传递 NoneTD = TypedDict("TD", None))自 Python 3.13 起已弃用。请使用 class TD(TypedDict): passTD = TypedDict("TD", {}) 来创建具有零字段的 TypedDict。

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

  • wave:

  • zipimport:

计划在 Python 3.16 中移除

计划在 Python 3.17 中移除

  • collections.abc:

    • collections.abc.ByteString 计划在 Python 3.17 中移除。

      要测试 obj 是否在运行时实现了缓冲区协议,请使用 isinstance(obj, collections.abc.Buffer)。在类型注解中,请使用 Buffer 或显式指定代码支持的类型的联合类型(例如 bytes | bytearray | memoryview)。

      ByteString 最初旨在作为 bytesbytearray 的超类型。然而,由于 ABC 从未有任何方法,知道一个对象是 ByteString 的实例实际上并不能告诉你任何关于该对象的有用信息。其他常见的缓冲区类型,如 memoryview,也从未被理解为 ByteString 的子类型(无论是运行时还是静态类型检查器)。

      有关更多详细信息,请参阅 PEP 688。(由 Shantanu Jain 在 gh-91896 贡献)。

  • typing:

    • 在 Python 3.14 之前,旧式联合类型是通过私有类 typing._UnionGenericAlias 实现的。该类对于实现已不再需要,但为了向后兼容而保留,并计划在 Python 3.17 中移除。用户应使用文档化的内省辅助工具,如 typing.get_origin()typing.get_args(),而不是依赖于私有实现细节。

    • typing.ByteString,自 Python 3.9 起已弃用,计划在 Python 3.17 中移除。

      要测试 obj 是否在运行时实现了缓冲区协议,请使用 isinstance(obj, collections.abc.Buffer)。在类型注解中,请使用 Buffer 或显式指定代码支持的类型的联合类型(例如 bytes | bytearray | memoryview)。

      ByteString 最初旨在作为 bytesbytearray 的超类型。然而,由于 ABC 从未有任何方法,知道一个对象是 ByteString 的实例实际上并不能告诉你任何关于该对象的有用信息。其他常见的缓冲区类型,如 memoryview,也从未被理解为 ByteString 的子类型(无论是运行时还是静态类型检查器)。

      有关更多详细信息,请参阅 PEP 688。(由 Shantanu Jain 在 gh-91896 贡献)。

计划在未来版本中移除

以下 API 将在未来移除,但目前尚未确定移除日期。

  • argparse:

    • 嵌套参数组和嵌套互斥组的做法已被弃用。

    • add_argument_group() 传递未写入文档的关键字参数 prefix_chars 的做法现已弃用。

    • argparse.FileType 类型转换器已被弃用。

  • builtins:

    • 生成器: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() 构造函数中将复数作为 realimag 参数传递的做法现已弃用;它应该仅作为单个位置参数传递。(由 Serhiy Storchaka 在 gh-109218 中贡献。)

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

  • codecs:请使用 open() 而不是 codecs.open()。(gh-133038

  • codeobject.co_lnotab:请改用 codeobject.co_lines() 方法。

  • datetime:

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

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

  • gettext:复数值必须是整数。

  • importlib:

  • importlib.metadata:

    • EntryPoints 元组接口。

    • 返回值的隐式 None

  • loggingwarn() 方法已自 Python 3.3 起弃用,请改用 warning()

  • mailbox:使用 StringIO 输入和文本模式已被弃用,请改用 BytesIO 和二进制模式。

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

  • pydoc.ErrorDuringImportexc_info 参数使用元组值的做法已被弃用,请改用异常实例。

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

  • sre_compilesre_constantssre_parse 模块。

  • shutilrmtree()onerror 参数在 Python 3.12 中已弃用;请改用 onexc 参数。

  • ssl 选项和协议

    • 不带协议参数的 ssl.SSLContext 已被弃用。

    • ssl.SSLContext: set_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

  • threading 方法

  • typing.Text (gh-92332)。

  • 内部类 typing._UnionGenericAlias 不再用于实现 typing.Union。为了保持与使用此私有类的用户的兼容性,将提供一个兼容性垫片,至少持续到 Python 3.17。(由 Jelle Zijlstra 在 gh-105499 中贡献。)

  • unittest.IsolatedAsyncioTestCase:从测试用例返回非 None 的值已被弃用。

  • urllib.parse 中已弃用的函数:请改用 urlparse()

    • splitattr()

    • splithost()

    • splitnport()

    • splitpasswd()

    • splitport()

    • splitquery()

    • splittag()

    • splittype()

    • splituser()

    • splitvalue()

    • to_bytes()

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

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

  • sys._clear_type_cache() 已被弃用:请改用 sys._clear_internal_caches()

已移除

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-based (和 distutils-based) 包仍然可以通过 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

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

    sqlite3.OptimizedUnicode 文本工厂自 Python 3.3 起已成为 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 中已弃用。OpenSSL 自 Python 3.7 起执行主机名匹配,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 以及 Firefox 35 及以下版本(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 中贡献。)

  • 移除几个标准库模块和测试中 Jython 兼容性补丁。(由 Nikita Sobolev 在 gh-99482 中贡献。)

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

移植到 Python 3.12

本节列出了前面描述过的变更以及其他可能需要修改代码的 bug 修复。

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 中描述的令牌:FSTRING_STARTFSTRING_MIDDLEFSTRING_END 现在除了表达式组件中分词的适当令牌外,还为 f-字符串“字符串”部分发出。例如,对于 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 变量,以在 make install 中覆盖 compileall 选项(默认值:-j0)。还将 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_BUILD_CORE 一起使用时,这现在会将引用计数初始化为

      _Py_IMMORTAL_REFCNT

    • SSTATE_INTERNED_IMMORTAL 已intern unicode 对象的标识符

      是不朽的。

    • SSTATE_INTERNED_IMMORTAL_STATIC 已intern unicode 对象的标识符

      是不朽且静态的

    • sys.getunicodeinternedsize 这返回已intern的 unicode 对象的总数

      已intern。现在需要它才能使 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* 的格式(例如 uZ)。请迁移到其他 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 中移除

预计在 Python 3.16 中移除

  • 捆绑的 libmpdec 副本。

预计在未来版本中移除

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