Python 3.12 有什么新变化

发布时间:2023年12月21日

Python 3.12 有什么新变化

本文介绍 Python 3.12 相比 3.11 增加的新特性。 Python 3.12 已于 2023 年 10 月 2 日发布。 要获取详细信息,可参阅?changelog

参见

PEP 693?-- Python 3.12 发布计划

摘要 -- 发布重点

Python 3.12 是 Python 编程语言的最新稳定发布版,包含一系列对语言和标准库的改变。 库的改变主要集中在清理已弃用的 API、可用性和正确性等方面。 值得注意的是,distutils?包已从标准库中移除。?os?和?pathlib?中的文件系统支持增加了许多改进,而且部分模块的性能也获得了提升。

语言的改变主要集中在可用性方面,如?f-字符串?的许多限制已被移除,而 'Did you mean ...' 提示消息继续得到改进。 新的?类型形参语法?和?type?语句提升了?泛型类型?和?类型别名?配合静态类型检查器使用时的效率。

本文并不试图提供所有新功能的完整规范说明,而是提供一个方便的概览。 如需了解完整细节,请参阅相应文档,如?标准库参考?和?语言参考。 如果你想了解某项改变的完整实现和设计理念,请参阅相应新特性的 PEP;但请注意一旦某项特性已完全实现则相应 PEP 通常不会再继续更新。


新的语法特性:

新的语法特性:

解释器的改进:

对 Python 数据模型的改进:

标准库中的重大改进:

安全改进:

  • 用来自?HACL*?项目的经过正式验证的代码替代 SHA1, SHA3, SHA2-384, SHA2-512 和 MD5 的内置?hashlib?实现。 这些内置实现保留作为仅在当 OpenSSL 未提供它们时使用的回退选项。

C API 的改进:

CPython 实现的改进:

  • PEP 709,推导式内联化

  • 对 Linux?perf?性能分析器的?CPython 支持

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

新的类型标注特性:

重要的弃用、移除或限制:

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

  • PEP 632: 移除?distutils?包。 请参阅?迁移指南?了解有关替换其所提供的 API 的建议。 第三方?Setuptools?包将继续提供?distutils,如果你在 Python 3.12 及更高版本中仍然需要它的话。

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

  • 移除了?asynchatasyncore?和?imp?模块,以及一些?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]

类型别名也可以是?generic:

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

新语法允许声明?TypeVarTuple?和?ParamSpec?形参,以及带边界或约束的?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}),因为这些序列包含?\N?部分,而这部分以前不能作为 f-字符串表达式组件的一部分。 现在,你可以这样定义表达式:

    >>>
    >>> 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 将包括在父函数的符号表中。

  • 在推导式内部调用?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'?
    

有关类型提示的新增特性

本节介绍了影响?类型提示?和?typing?模块的主要更改。

PEP 692: 使用?TypedDict?进行更精确的?**kwargs?类型标注

在函数签名中的?**kwargs?类型标注(由?PEP 484?引入)只允许在所有?**kwargs?都属于同一类型的情况下进行有效标注。

PEP 692?通过依赖类型化的字典规定了一种更精确的针对?**kwargs?的类型标注方式:

from typing import TypedDict, Unpack

class Movie(TypedDict):
  name: str
  year: int

def foo(**kwargs: Unpack[Movie]): ...

更多细节请参见?PEP 692

(由 Franek Magiera 在?gh-103629?中贡献。)

PEP 698:覆盖静态类型的装饰器

一个新的装饰器?typing.override()?已添加到?typing?模块中。 它向类型检查器指示该方法旨在重写超类中的方法。 这允许类型检查器在打算重写基类中的某个方法实际上没有重写的情况下捕获错误。

示例:

from typing import override

class Base:
  def get_color(self) -> str:
    return "blue"

class GoodChild(Base):
  @override  # ok: overrides Base.get_color
  def get_color(self) -> str:
    return "yellow"

class BadChild(Base):
  @override  # type checker error: does not override Base.get_color
  def get_colour(self) -> str:
    return "red"

更多细节参见?PEP 698

(由 Steven Troxler 在?gh-101561?中贡献。)

其他语言特性修改

  • 解析器现在在解析包含空字节的源代码时引发?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-breaker 机制上运行,而不是在对象分配上运行。 垃圾回收也可以在调用?PyErr_CheckSignals()?时运行,因此需要长时间运行而不执行任何 Python 代码的 C 扩展也有机会定期执行垃圾回收。 (由 Pablo Galindo 在?gh-97922?中贡献。)

  • 所有期望布尔参数的内置和扩展可调用函数现在都接受任何类型的参数,而不仅仅是?bool?和?int。 (由 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 在?gh-96123?中贡献并包含来自 Gregory P. Smith [Google] 和 Mark Shannon 的帮助。)

新增模块

  • 无。

改进的模块

array

asyncio

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

pdb

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

random

shutil

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

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

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

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

    在 Windows 上?shutil.which()?将在搜索路径的其他地方直接匹配之前返回?cmd?与来自?PATHEXT?的组件相匹配的路径。 (由 Charles Machalow 在?gh-103179?中贡献。)

sqlite3

statistics

  • 扩展?statistics.correlation()?以?ranked?方法的形式包括对分级数据的斯皮尔曼相关性计算。 (由 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()?来查找属性是否存在。 这意味着描述器和?__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()?检测速度。

  • 针对?运行时可检测协议?的?isinstance()?检测的性能表现有显著的改进。 对于具有少量成员的协议的?isinstance()?检测相比 3.11 应当至少有 2x 的提速,有些可能会有 20x 或更多的提速。 但是,对于具有十四个或更多成员的协议的?isinstance()?检测可能会慢于 Python 3.11。 (由 Alex Waygood 在?gh-74690?和?gh-103193?中贡献。)

  • 现在所有?typing.TypedDict?和?typing.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 对象中移除了?wstr?和?wstr_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 project?中找到。 (由 Victor Stinner 在?gh-97681?中贡献。)

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

弃用

计划在 Python 3.13 中移除

以下模块和 API 已在之前的 Python 发布版中弃用,并将在 Python 3.13 中移除。

模块 (参见?PEP 594):

其他模块:

  • lib2to3,以及?2to3?程序 (gh-84540)

API:

计划在 Python 3.14 中移除

以下 API 已被弃用并将在 Python 3.14 中移除。

  • argparse:?argparse.BooleanOptionalAction?的?type,?choices?和?metavar?形参

  • ast:

    • ast.Num

    • ast.Str

    • ast.Bytes

    • ast.NameConstant

    • ast.Ellipsis

  • asyncio:

    • asyncio.MultiLoopChildWatcher

    • asyncio.FastChildWatcher

    • asyncio.AbstractChildWatcher

    • asyncio.SafeChildWatcher

    • asyncio.set_child_watcher()

    • asyncio.get_child_watcher(),

    • asyncio.AbstractEventLoopPolicy.set_child_watcher()

    • asyncio.AbstractEventLoopPolicy.get_child_watcher()

  • collections.abc:?collections.abc.ByteString

  • email:?email.utils.localtime()?中的?isdst?形参。

  • importlib.abc:

    • importlib.abc.ResourceReader

    • importlib.abc.Traversable

    • importlib.abc.TraversableResources

  • itertools: 对 copy, deepcopy 和 pickle 操作的支持。

  • pkgutil:

    • pkgutil.find_loader()

    • pkgutil.get_loader()

  • pty:

    • pty.master_open()

    • pty.slave_open()

  • shutil:?shutil.rmtree()?的?onerror?参数

  • typing:?typing.ByteString

  • xml.etree.ElementTree: 对?xml.etree.ElementTree.Element?的真值测试。

  • 模块对象上的?__package__?和?__cached__?属性。

  • 代码对象的?co_lnotab?属性。

Python 3.15 中的待移除功能

以下 API 已被弃用并将在 Python 3.15 中移除。

API:

计划在未来版本中移除

下列 API 在更早的 Python 版本中已被弃用并将被移除,但目前还没有确定它们的移除日期。

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

  • typing.Text?(gh-92332)

  • 目前 Python 接受数字类字面值后面紧跟关键字的写法,例如?0in?x,?1or?x,?0if?1else?2。 它将允许像?[0x1for?x?in?y]?这样令人困惑且模棱两可的表达式 (它可以被解读为?[0x1?for?x?in?y]?或者?[0x1f?or?x?in?y])。 从本发布版开始,如果数字类字面值后面紧跟关键字?and,?else,?for,?if,?in,?is?和?or?中的一个将会引发弃用警告。 在未来的版本中它将改为语法警告,最终将改为语法错误。 (gh-87999)

移除

asynchat 和 asyncore

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

configparser

distutils

  • 移除了?distutils?包。 它已在 Python 3.10 中根据?PEP 632?"Deprecate distutils module" 被弃用。 对于仍然使用?distutils?且无法升级为使用其他工具的项目,可以安装?setuptools?项目:它仍然提供了?distutils。 (由 Victor Stinner 在?gh-92584?中贡献。)

ensurepip

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

    pip?(>=?22.1)?不再要求在环境中安装 setuptools。 基于?setuptools?(和基于?distutils) 的包仍然可通过?pip?install?来使用,因为 pip 将在它用于构建包的构建环境中提供?setuptools

    在默认情况下由?venv?创建或通过?ensurepip?初始化的环境将不再提供?easy_install,?pkg_resources,?setuptools?和?distutils?包,因为它们是?setuptools?包的组成部分。 对于在运行时依赖这些包的项目,应当将?setuptools?项目声明为依赖项之一并单独安装(通常是使用 pip)。

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

enum

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

ftplib

  • 移除了?ftplib?的?FTP_TLS.ssl_version?类属性:请改用?context?形参。 (由 Victor Stinner 在?gh-94172?中贡献。)

gzip

  • 移除了?gzip?中?gzip.GzipFile?的?filename?属性,自 Python 2.6 起该属性已被弃用,请改用?name?属性。 在可写模式下,如果?filename?属性没有?'.gz'?文件扩展名则会添加它。 (由 Victor Stinner 在?gh-94196?中贡献。)

hashlib

  • 移除了?hashlib?中?hashlib.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_package,?importlib.util.set_loader?和?importlib.util.module_for_loader?均已被移除。 (由 Brett Cannon 和 Nikita Sobolev 在?gh-65961?和?gh-97850?中贡献。)

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

    • importlib.abc.Finder,?pkgutil.ImpImporter?和?pkgutil.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_SUFFIXES,?importlib.machinery.EXTENSION_SUFFIXES?和?importlib.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_ERROR,?PY_SOURCE,?PY_COMPILED,?C_EXTENSION,?PY_RESOURCE,?PKG_DIRECTORY,?C_BUILTIN,?PY_FROZEN,?PY_CODERESOURCE,?IMP_HOOK

io

  • 移除了?io?中的?io.OpenWrapper?和?_pyio.OpenWrapper,它们在 Python 3.10 中已被弃用:请改用?open()。?open()?(io.open()) 函数是一个内置函数。 自 Python 3.10 起,_pyio.open()?也是一个静态方法。 (由 Victor Stinner 在?gh-94169?中贡献。).)

locale

smtpd

  • smtpd?模块已按照?PEP 594?中的计划表被移除,它在 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

  • 移除了?ssl?的?ssl.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

  • 移除了?zipimport?的?find_loader()?和?find_module()?方法,它们在 Python 3.10 中已被弃用:请改用?find_spec()?方法。 请参阅?PEP 451?了解相关说明。 (由 Victor Stinner 在?gh-94379?中贡献。)

其他事项

  • 从文档?Makefile?和?Doc/tools/rstlint.py?中移除了?suspicious?规则,请改用?sphinx-lint。 (由 Julien Palard 在?gh-98179?中贡献。)

  • 移除了?ftplibimaplibpoplib?和?smtplib?模块中的?keyfile?和?certfile?形参数,以及?http.client?模块中的?key_filecert_file?和?check_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

本节列出了先前描述的更改以及可能需要更改代码的其他错误修正.

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)?调用)改为?filesystem encoding and error handler。 在 Windows 系统中参数文件应使用 UTF-8 而不是 ANSI 代码页来编码。

  • 移除在 Python 3.4.7 和 3.5.4 中被弃用的?asyncore-based?smtpd?模块。 推荐使用基于?asyncio?的?aiosmtpd?PyPI 模块作为替代。

  • shlex.split(): 传入?None?作为?s?参数现在将引发异常,而不是读取?sys.stdin。 该特性在 Python 3.9 中已被弃用。 (由 Victor Stinner 在?gh-94352?中贡献。)

  • os?模块不再接受类似字节串的路径,如?bytearray?和?memoryview?类型:只接受明确的?bytes?类型字节串。 (由 Victor Stinner 在?gh-98393?中贡献。)

  • 现在?syslog.openlog()?和?syslog.closelog()?如果在子解释器中使用将失败。?syslog.syslog()?仍可在子解释器中使用,但前提是?syslog.openlog()?已在主解释器中被调用。 这些新限制不适用于主解释器,因此只有少数用户可能会受到影响。 这一改变有助于实现解释器隔离。 此外,syslog?是一个针对进程全局资源的包装器,而这些资源最好是由主解释器来管理。 (由 Donghee Na 在?gh-99127?中贡献。)

  • 未写入文档的?cached_property()?的锁定行为已被移除,因为该行为会在类的所有实例中锁定,从而导致高锁定争用。 这意味着如果两个线程同时运行,缓存属性获取函数现在可以在单个实例中运行不止一次。 对于大多数简单的缓存属性(例如那些幂等的并且只需根据实例的其他属性计算一个值的属性)来说这是没有问题的。 如果需要同步,可在缓存属性获取函数中或多线程访问点周围实现锁定操作。

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

  • 当使用?tarfile?或?shutil.unpack_archive()?提取 tar 文件时,请传入?filter?参数来限制可能令人感到意外或危险的特性。 请参阅?解压缩过滤器?了解详情。

  • 由于在?PEP 701?中引入的更改?tokenize.tokenize()?和?tokenize.generate_tokens()?函数的输出现在发生了改变。 这意味着不再为 f-字符输出?STRING?词元而是改为产生?PEP 701?中描述的词元:除了用于对表达式组件进行分词的适当词元外现在还有?FSTRING_START,?FSTRING_MIDDLE?和?FSTRING_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 编译器接受 ThinLTO 选项则 CPython 会将其作为默认的链接时间优化策略。 (由 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_IMMORTAL_REFCNT?当配合?Py_BUILD_CORE?使用时。

    • SSTATE_INTERNED_IMMORTAL?一个针对内部 unicode 对象的标识符

      为永生对象。

    • SSTATE_INTERNED_IMMORTAL_STATIC?一个针对内部 unicode

      为永生且静态的对象

    • sys.getunicodeinternedsize?这将返回总计的 unicode

      被管理的对象。现在?refleak.py?需要这样才能正确地追踪引用计数和分配的块

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

  • PEP 684: 新增了?Py_NewInterpreterFromConfig()?函数和?PyInterpreterConfig,可用于创建具有单独 GIL 的子解释器。 (更多信息参见?PEP 684: 解释器级 GIL。) (由 Eric Snow 在?gh-104110?中贡献。)

  • 在 3.12 版的受限 C API 中,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 格式如?s,?z,?es?和?U

  • 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_DICT?和?Py_TPFLAGS_MANAGED_WEAKREF?来代替?tp_dictoffset?和?tp_weaklistoffset。 目前仍支持使用?tp_dictoffset?和?tp_weaklistoffset,但并不完全支持多重继承 (gh-95589),而且性能可能会变差。 声明了?Py_TPFLAGS_MANAGED_DICT?的类应当调用?_PyObject_VisitManagedDict()?和?_PyObject_ClearManagedDict()?来遍历并清除它们的实例的字典。 要清除弱引用,请像之前一样调用?PyObject_ClearWeakRefs()

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

  • Py_CLEARPy_SETREF?和?Py_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_InputHook?和?PyOS_ReadlineFunctionPointer?将不再在?子解释器?中被调用。 这是因为客户端通常依赖进程级的全局状态(而这些回调没有办法恢复扩展模块状态)。

    这也避免了扩展程序在不支持(或尚未被加载)的子解释器中运行的情况。 请参阅?gh-104668?了解更多信息。

  • PyLongObject?对其内部字段进行了修改以提高性能。 虽然?PyLongObject?的内部字段是私有的,但某些扩展模块会使用它们。 内部字段不应再被直接访问,而应改用以?PyLong_...?打头的 API 函数。 新增了两个?暂定?API 函数用于高效访问适配至单个机器字的?PyLongObject?的值:

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

弃用

计划在 Python 3.14 中移除
Python 3.15 中的待移除功能
计划在未来版本中移除

以下 API 已被弃用,将被移除,但目前尚未确定移除日期。

移除

  • 移除?token.h?头文件。从来就没有任何公开的 C 语言标记程序接口。?token.h?头文件只是为 Python 内部使用而设计的。(由 Victor Stinner 在?gh-92651?提供)。

  • 旧式 Unicode API 已被移除。 请参阅?PEP 623?了解详情。for detail.

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

文章来源:https://blog.csdn.net/TalorSwfit20111208/article/details/135116875
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。