Python 3.9 中的新特性

编辑:

Łukasz Langa

本文解释了 Python 3.9 相较于 3.8 的新特性。Python 3.9 于 2020 年 10 月 5 日发布。有关完整详细信息,请参阅更新日志

参见

PEP 596 - Python 3.9 发布时间表

摘要 – 发布亮点

新语法功能

  • PEP 584,向 dict 添加了联合运算符;

  • PEP 585,标准集合中的类型提示泛型;

  • PEP 614,放宽了装饰器的语法限制。

新的内置功能

  • PEP 616,用于删除前缀和后缀的字符串方法。

标准库中的新功能

  • PEP 593,灵活的函数和变量注解;

  • 添加了os.pidfd_open(),允许在没有竞争条件和信号的情况下进行进程管理。

解释器的改进

  • PEP 573,从 C 扩展类型方法快速访问模块状态;

  • PEP 617,CPython 现在使用基于 PEG 的新解析器;

  • 一些 Python 内置类型(range、tuple、set、frozenset、list、dict)现在使用PEP 590 vectorcall 加速;

  • 垃圾回收不再阻塞复活的对象;

  • 许多 Python 模块(_abcaudioop_bz2_codecs_contextvars_crypt_functools_json_localemathoperatorresourcetime_weakref)现在使用 PEP 489 定义的多阶段初始化;

  • 许多标准库模块(audioopastgrp_hashlibpwd_posixsubprocessrandomselectstructtermioszlib)现在使用 PEP 384 定义的稳定 ABI。

新库模块

  • PEP 615,IANA 时区数据库现在在标准库中的 zoneinfo 模块中;

  • 新的 graphlib 模块中提供了图的拓扑排序实现。

发布过程变更

  • PEP 602,CPython 采用年度发布周期。

您应该检查代码中的 DeprecationWarning

当 Python 2.7 仍受支持时,Python 3 中的许多功能都保留下来,以向后兼容 Python 2.7。随着 Python 2 支持的结束,这些向后兼容层已被移除或将很快移除。其中大部分已在几年内发出了 DeprecationWarning 警告。例如,自 2012 年发布的 Python 3.3 以来,使用 collections.Mapping 而不是 collections.abc.Mapping 就会发出 DeprecationWarning

使用 -W default 命令行选项测试您的应用程序,以查看 DeprecationWarningPendingDeprecationWarning,甚至可以使用 -W error 将它们视为错误。警告过滤器可用于忽略第三方代码的警告。

Python 3.9 是最后一个提供这些 Python 2 向后兼容层的版本,以便为 Python 项目维护者提供更多时间来组织移除 Python 2 支持并添加对 Python 3.9 的支持。

collections 模块中 抽象基类 的别名,例如 collections.Mapping 别名到 collections.abc.Mapping,为了向后兼容性,将保留到最后一个版本。它们将在 Python 3.10 中移除。

更一般地,尝试在Python 开发模式中运行测试,这有助于准备代码以使其与下一个 Python 版本兼容。

注意:此版本的 Python 中也移除了一些已有的弃用。请参阅移除部分。

新功能

字典合并与更新操作符

合并 (|) 和更新 (|=) 操作符已添加到内置的 dict 类中。它们补充了现有的 dict.update{**d1, **d2} 合并字典的方法。

示例

>>> x = {"key1": "value1 from x", "key2": "value2 from x"}
>>> y = {"key2": "value2 from y", "key3": "value3 from y"}
>>> x | y
{'key1': 'value1 from x', 'key2': 'value2 from y', 'key3': 'value3 from y'}
>>> y | x
{'key2': 'value2 from x', 'key3': 'value3 from y', 'key1': 'value1 from x'}

有关完整说明,请参阅PEP 584。(由 Brandt Bucher 在bpo-36144中贡献。)

新的字符串方法,用于删除前缀和后缀

已添加 str.removeprefix(prefix)str.removesuffix(suffix),以便轻松从字符串中删除不需要的前缀或后缀。相应的 bytesbytearraycollections.UserString 方法也已添加。有关完整说明,请参阅PEP 616。(由 Dennis Sweeney 在bpo-39939中贡献。)

标准集合中的类型提示泛型

在类型注解中,您现在可以使用内置的集合类型,例如 listdict 作为泛型类型,而不是从 typing 中导入相应的首字母大写的类型(例如 ListDict)。标准库中的其他一些类型现在也是泛型的,例如 queue.Queue

示例

def greet_all(names: list[str]) -> None:
    for name in names:
        print("Hello", name)

有关更多详细信息,请参阅PEP 585。(由 Guido van Rossum、Ethan Smith 和 Batuhan Taşkaya 在bpo-39481中贡献。)

新解析器

Python 3.9 使用一个新的解析器,基于 PEG 而不是 LL(1)。新解析器的性能大致与旧解析器相当,但在设计新语言功能时,PEG 形式比 LL(1) 更灵活。我们将在 Python 3.10 及更高版本中开始利用这种灵活性。

ast 模块使用新解析器并生成与旧解析器相同的 AST。

在 Python 3.10 中,旧解析器将被删除,所有依赖于它的功能(主要是 parser 模块,该模块早已弃用)也将被删除。仅在 Python 3.9 中,您可以使用命令行开关 (-X oldparser) 或环境变量 (PYTHONOLDPARSER=1) 切换回 LL(1) 解析器。

有关更多详细信息,请参阅PEP 617。(由 Guido van Rossum、Pablo Galindo 和 Lysandros Nikolaou 在bpo-40334中贡献。)

其他语言更改

  • __import__() 现在引发 ImportError,而不是 ValueError,以前当相对导入超出其顶级包时会发生这种情况。(由 Ngalim Siregar 在bpo-37444中贡献。)

  • Python 现在获取命令行上指定的脚本文件名的绝对路径(例如:python3 script.py):__main__ 模块的 __file__ 属性变为绝对路径,而不是相对路径。在通过 os.chdir() 更改当前目录后,这些路径仍然有效。作为副作用,在这种情况下,回溯还显示 __main__ 模块帧的绝对路径。(由 Victor Stinner 在bpo-20443中贡献。)

  • Python 开发模式调试构建中,现在会检查字符串编码和解码操作的 encodingerrors 参数。例如:open()str.encode()bytes.decode()

    默认情况下,为了获得最佳性能,仅在第一次编码/解码错误时检查 errors 参数,并且有时会忽略空字符串的 encoding 参数。(由 Victor Stinner 在bpo-37388中贡献。)

  • "".replace("", s, n) 现在对于所有非零 n 返回 s 而不是空字符串。它现在与 "".replace("", s) 一致。bytesbytearray 对象也有类似的更改。(由 Serhiy Storchaka 在bpo-28029中贡献。)

  • 任何有效的表达式现在都可以用作装饰器。以前,语法更加严格。有关详细信息,请参阅PEP 614。(由 Brandt Bucher 在bpo-39702中贡献。)

  • 改进了 typing 模块的帮助。现在为所有特殊形式和特殊泛型别名(如 UnionList)显示 docstring。将 help() 与泛型别名(如 List[int])一起使用将显示相应具体类型(本例中为 list)的帮助。(由 Serhiy Storchaka 在bpo-40257中贡献。)

  • 现在禁止并行运行 aclose() / asend() / athrow(),并且 ag_running 现在反映异步生成器的实际运行状态。(由 Yury Selivanov 在bpo-30773中贡献。)

  • in 运算符和 operator 模块的函数 contains()indexOf()countOf() 中,调用 __iter__ 方法时出现的意外错误不再被 TypeError 掩盖。(由 Serhiy Storchaka 在bpo-40824中贡献。)

  • 未加括号的 lambda 表达式不能再用作列表推导式和生成器表达式中 if 子句的表达式部分。有关详细信息,请参阅 bpo-41848bpo-43755

新模块

zoneinfo

zoneinfo 模块为标准库带来了对 IANA 时区数据库的支持。它添加了 zoneinfo.ZoneInfo,这是一个由系统时区数据支持的具体 datetime.tzinfo 实现。

示例

>>> from zoneinfo import ZoneInfo
>>> from datetime import datetime, timedelta

>>> # Daylight saving time
>>> dt = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles"))
>>> print(dt)
2020-10-31 12:00:00-07:00
>>> dt.tzname()
'PDT'

>>> # Standard time
>>> dt += timedelta(days=7)
>>> print(dt)
2020-11-07 12:00:00-08:00
>>> print(dt.tzname())
PST

作为未提供 IANA 数据库的平台的数据回退源,tzdata 模块作为第一方包发布——通过 PyPI 分发并由 CPython 核心团队维护。

参见

PEP 615 – 标准库中对 IANA 时区数据库的支持

由 Paul Ganssle 撰写并实现的 PEP

graphlib

添加了一个新模块 graphlib,其中包含 graphlib.TopologicalSorter 类,提供图的拓扑排序功能。(由 Pablo Galindo、Tim Peters 和 Larry Hastings 在bpo-17005中贡献。)

改进的模块

ast

dump() 添加了 indent 选项,允许其生成多行缩进输出。(由 Serhiy Storchaka 在bpo-37995中贡献。)

ast 模块中添加了 ast.unparse() 函数,该函数可用于解析 ast.AST 对象并生成一个字符串代码,该代码在解析时将生成等效的 ast.AST 对象。(由 Pablo Galindo 和 Batuhan Taskaya 在bpo-38870中贡献。)

为 AST 节点添加了 docstring,其中包含用于构建该节点的 ASDL 签名。(由 Batuhan Taskaya 在bpo-39638中贡献。)

asyncio

由于重大的安全问题,不再支持 asyncio.loop.create_datagram_endpoint()reuse_address 参数。这是由于 SO_REUSEADDR 套接字选项在 UDP 中的行为。有关更多详细信息,请参见 loop.create_datagram_endpoint() 的文档。(由 Kyle Stanley、Antoine Pitrou 和 Yury Selivanov 在 bpo-37228 中贡献。)

添加了一个新的协程 shutdown_default_executor(),它安排默认执行器的关闭,等待 ThreadPoolExecutor 完成关闭。此外,asyncio.run() 已更新以使用新的协程。(由 Kyle Stanley 在bpo-34037中贡献。)

增加了 asyncio.PidfdChildWatcher,一个特定于 Linux 的子进程监视器实现,它轮询进程文件描述符。(bpo-38692

添加了一个新的协程 asyncio.to_thread()。它主要用于在单独的线程中运行 I/O 密集型函数,以避免阻塞事件循环,并且本质上是 run_in_executor() 的高级版本,可以直接接受关键字参数。(由 Kyle Stanley 和 Yury Selivanov 在bpo-32309中贡献。)

由于超时而取消任务时,asyncio.wait_for() 现在将等待取消完成,即使 timeout 小于等于 0,就像它处理正超时一样。(由 Elvis Pranskevichus 在bpo-32751中贡献。)

asyncio 现在在调用与 ssl.SSLSocket 套接字不兼容的方法时引发 TypeError。(由 Ido Michael 在bpo-37404中贡献。)

compileall

增加了对重复 .pyc 文件使用硬链接的新可能性:hardlink_dupes 参数和 –hardlink-dupes 命令行选项。(由 Lumír ‘Frenzy’ Balhar 在bpo-40495中贡献。)

添加了用于在生成的 .pyc 文件中进行路径操作的新选项:stripdirprependdirlimit_sl_dest 参数以及 -s、-p、-e 命令行选项。添加了多次指定优化级别选项的可能性。(由 Lumír ‘Frenzy’ Balhar 在bpo-38112中贡献。)

concurrent.futures

concurrent.futures.Executor.shutdown() 添加了一个新的 cancel_futures 参数,该参数取消所有尚未开始运行的待处理 future,而不是等待它们完成才关闭执行器。(由 Kyle Stanley 在bpo-39349中贡献。)

ThreadPoolExecutorProcessPoolExecutor 中移除了守护线程。这改善了与子解释器的兼容性以及其关闭过程的可预测性。(由 Kyle Stanley 在bpo-39812中贡献。)

ProcessPoolExecutor 中的工作进程现在按需生成,仅当没有可用的空闲工作进程可重用时。这优化了启动开销并减少了因空闲工作进程而损失的 CPU 时间。(由 Kyle Stanley 在bpo-39207中贡献。)

curses

添加了 curses.get_escdelay()curses.set_escdelay()curses.get_tabsize()curses.set_tabsize() 函数。(由 Anthony Sottile 在bpo-38312中贡献。)

datetime

datetime.dateisocalendar() 方法和 datetime.datetimeisocalendar() 方法现在返回 namedtuple() 而不是 tuple。(由 Donghee Na 在bpo-24416中贡献。)

distutils

upload 命令现在创建 SHA2-256 和 Blake2b-256 哈希摘要。它在阻止 MD5 摘要的平台上跳过 MD5。(由 Christian Heimes 在bpo-40698中贡献。)

fcntl

添加了常量 fcntl.F_OFD_GETLKfcntl.F_OFD_SETLKfcntl.F_OFD_SETLKW。(由 Donghee Na 在bpo-38602中贡献。)

ftplib

FTPFTP_TLS 现在,如果其构造函数给定的超时为零,则会引发 ValueError,以防止创建非阻塞套接字。(由 Donghee Na 在bpo-39259中贡献。)

gc

当垃圾回收器进行回收时,如果一些对象复活(在终结器执行后,它们可以从隔离的循环外部访问),则不会阻止所有仍然无法访问的对象的回收。(由 Pablo Galindo 和 Tim Peters 在bpo-38379中贡献。)

添加了一个新函数 gc.is_finalized() 来检查对象是否已被垃圾回收器终结。(由 Pablo Galindo 在bpo-39322中贡献。)

hashlib

hashlib 模块现在可以在可用时使用 OpenSSL 的 SHA3 哈希和 SHAKE XOF。(由 Christian Heimes 在bpo-37630中贡献。)

内置哈希模块现在可以通过 ./configure --without-builtin-hashlib-hashes 禁用,或者通过例如 ./configure --with-builtin-hashlib-hashes=sha3,blake2 有选择地启用,以强制使用基于 OpenSSL 的实现。(由 Christian Heimes 在bpo-40479中贡献)

http

HTTP 状态码 103 EARLY_HINTS418 IM_A_TEAPOT425 TOO_EARLY 已添加到 http.HTTPStatus。(由 Donghee Na 在bpo-39509和 Ross Rhodes 在bpo-39507中贡献。)

IDLE 和 idlelib

添加了关闭光标闪烁的选项。(由 Zackery Spytz 在bpo-4603中贡献。)

Escape 键现在关闭 IDLE 补全窗口。(由 Johnny Najera 在bpo-38944中贡献。)

添加了关键字到模块名补全列表。(由 Terry J. Reedy 在bpo-37765中贡献。)

3.9 维护版本中的新功能

使 IDLE 调用 sys.excepthook()(在不带“-n”启动时)。以前用户钩子会被忽略。(由 Ken Hilton 在bpo-43008中贡献。)

上述更改已反向移植到 3.8 维护版本。

重新排列设置对话框。将“常规”选项卡拆分为“窗口”和“Shell/Ed”选项卡。将扩展“帮助”菜单的帮助源移动到“扩展”选项卡。为新选项腾出空间并缩短对话框。后者使对话框更好地适应小屏幕。(由 Terry Jan Reedy 在bpo-40468中贡献。)将缩进空间设置从“字体”选项卡移动到新的“窗口”选项卡。(由 Mark Roseman 和 Terry Jan Reedy 在bpo-33962中贡献。)

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

imaplib

IMAP4IMAP4_SSL 的构造函数现在具有一个可选的 timeout 参数。此外,open() 方法现在也具有一个可选的 timeout 参数。此更改已应用于 IMAP4_SSLIMAP4_stream 的重写方法。(由 Donghee Na 在bpo-38615中贡献。)

添加了 imaplib.IMAP4.unselect()imaplib.IMAP4.unselect() 释放与所选邮箱关联的服务器资源,并将服务器返回到已认证状态。此命令执行与 imaplib.IMAP4.close() 相同的操作,但不会从当前选定邮箱中永久移除任何消息。(由 Donghee Na 在bpo-40375中贡献。)

importlib

为了提高与 import 语句的一致性,importlib.util.resolve_name() 现在对于无效的相对导入尝试会引发 ImportError 而不是 ValueError。(由 Ngalim Siregar 在bpo-37444中贡献。)

发布不可变模块对象的导入加载器现在除了单个模块外,还可以发布不可变包。(由 Dino Viehland 在bpo-39336中贡献。)

添加了 importlib.resources.files() 函数,支持包数据中的子目录,与 importlib_resources 1.5 版本中的反向移植匹配。(由 Jason R. Coombs 在bpo-39791中贡献。)

importlib_metadata 1.6.1 版本刷新了 importlib.metadata

inspect

inspect.BoundArguments.argumentsOrderedDict 更改为普通 dict。(由 Inada Naoki 在bpo-36350bpo-39775中贡献。)

ipaddress

ipaddress 现在支持 IPv6 范围地址(带有后缀 %<scope_id> 的 IPv6 地址)。

可以使用 ipaddress.IPv6Address 解析范围 IPv6 地址。如果存在,可以通过 scope_id 属性获取范围区域 ID。(由 Oleksandr Pavliuk 在bpo-34788中贡献。)

从 Python 3.9.5 开始,ipaddress 模块不再接受 IPv4 地址字符串中的任何前导零。(由 Christian Heimes 在bpo-36384中贡献)。

math

扩展了 math.gcd() 函数以处理多个参数。以前,它只支持两个参数。(由 Serhiy Storchaka 在bpo-39648中贡献。)

添加了 math.lcm():返回指定参数的最小公倍数。(由 Mark Dickinson、Ananthakrishnan 和 Serhiy Storchaka 在bpo-39479bpo-39648中贡献。)

添加了 math.nextafter():返回 x 之后朝向 y 的下一个浮点值。(由 Victor Stinner 在bpo-39288中贡献。)

添加了 math.ulp():返回浮点数最低有效位的值。(由 Victor Stinner 在bpo-39310中贡献。)

multiprocessing

multiprocessing.SimpleQueue 类有一个新的 close() 方法,用于显式关闭队列。(由 Victor Stinner 在bpo-30966中贡献。)

nntplib

NNTPNNTP_SSL 现在,如果其构造函数给定的超时为零,则会引发 ValueError,以防止创建非阻塞套接字。(由 Donghee Na 在bpo-39259中贡献。)

os

si_code 添加了 CLD_KILLEDCLD_STOPPED。(由 Donghee Na 在bpo-38493中贡献。)

公开了特定于 Linux 的 os.pidfd_open() (bpo-38692) 和 os.P_PIDFD (bpo-38713),用于通过文件描述符进行进程管理。

os.unsetenv() 函数现在在 Windows 上也可用。(由 Victor Stinner 在bpo-39413中贡献。)

os.putenv()os.unsetenv() 函数现在始终可用。(由 Victor Stinner 在bpo-39395中贡献。)

添加了 os.waitstatus_to_exitcode() 函数:将等待状态转换为退出代码。(由 Victor Stinner 在bpo-40094中贡献。)

pathlib

添加了 pathlib.Path.readlink(),其行为类似于 os.readlink()。(由 Girts Folkmanis 在bpo-30618中贡献)

pdb

在 Windows 上,Pdb 现在支持 ~/.pdbrc。(由 Tim Hopper 和 Dan Lidral-Porter 在bpo-20523中贡献。)

poplib

POP3POP3_SSL 现在,如果其构造函数给定的超时为零,则会引发 ValueError,以防止创建非阻塞套接字。(由 Donghee Na 在bpo-39259中贡献。)

pprint

pprint 现在可以美观地打印 types.SimpleNamespace。(由 Carl Bordum Hansen 在bpo-37376中贡献。)

pydoc

现在,文档字符串不仅显示类、函数、方法等,还显示任何具有自己的 __doc__ 属性的对象。(由 Serhiy Storchaka 在bpo-40257中贡献。)

random

添加了一个新的 random.Random.randbytes() 方法:生成随机字节。(由 Victor Stinner 在bpo-40286中贡献。)

信号

公开了特定于 Linux 的 signal.pidfd_send_signal(),用于使用文件描述符而不是 pid 向进程发送信号。(bpo-38712

smtplib

SMTPSMTP_SSL 现在,如果其构造函数给定的超时为零,则会引发 ValueError,以防止创建非阻塞套接字。(由 Donghee Na 在bpo-39259中贡献。)

LMTP 构造函数现在有一个可选的 timeout 参数。(由 Donghee Na 在bpo-39329中贡献。)

socket

socket 模块现在在 Linux 4.1 及更高版本上导出 CAN_RAW_JOIN_FILTERS 常量。(由 Stefan Tatschner 和 Zackery Spytz 在bpo-25780中贡献。)

socket 模块现在支持 CAN_J1939 协议,只要平台支持它。(由 Karl Ding 在bpo-40291中贡献。)

socket 模块现在有 socket.send_fds()socket.recv_fds() 函数。(由 Joannah Nanjekye、Shinya Okano 和 Victor Stinner 在bpo-28724中贡献。)

时间

在 AIX 上,thread_time() 现在使用具有纳秒分辨率的 thread_cputime() 实现,而不是具有 10 毫秒分辨率的 clock_gettime(CLOCK_THREAD_CPUTIME_ID)。(由 Batuhan Taskaya 在bpo-40192中贡献)

sys

添加了一个新的 sys.platlibdir 属性:平台特定库目录的名称。它用于构建标准库的路径和已安装扩展模块的路径。在大多数平台上,它等于 "lib"。在 Fedora 和 SuSE 上,在 64 位平台上,它等于 "lib64"。(由 Jan Matějek、Matěj Cepl、Charalampos Stratakis 和 Victor Stinner 在bpo-1294959中贡献。)

以前,非交互式时,sys.stderr 是块缓冲的。现在 stderr 默认为始终行缓冲。(由 Jendrik Seipp 在bpo-13601中贡献。)

tracemalloc

添加了 tracemalloc.reset_peak(),用于将跟踪内存块的峰值大小设置为当前大小,以测量特定代码段的峰值。(由 Huon Wilson 在bpo-40630中贡献。)

typing

PEP 593 引入了 typing.Annotated 类型,用于使用上下文特定元数据装饰现有类型,并向 typing.get_type_hints() 添加了新的 include_extras 参数,以在运行时访问元数据。(由 Till Varoquaux 和 Konstantin Kashin 贡献。)

unicodedata

Unicode 数据库已更新到版本 13.0.0。(bpo-39926)。

venv

venv 提供的激活脚本现在都通过始终使用 __VENV_PROMPT__ 指定的值来一致地定制其提示。以前,一些脚本无条件使用 __VENV_PROMPT__,另一些仅在恰好设置时使用(这是默认情况),一个则使用 __VENV_NAME__。 (由 Brett Cannon 在bpo-37663中贡献。)

xml

xml.etree.ElementTree 序列化为 XML 文件时,属性中的空格字符现在会保留。换行符不再标准化为“n”。这是关于如何解释 XML 规范第 2.11 节的讨论结果。(由 Mefistotelis 在bpo-39011中贡献。)

优化

  • 优化了列表推导式中临时变量赋值的惯用语法。现在,列表推导式中的 for y in [expr] 与简单的赋值 y = expr 一样快。例如

    sums = [s for s in [0] for x in data for s in [s + x]]

    := 运算符不同,这种惯用语法不会将变量泄露到外部作用域。

    (由 Serhiy Storchaka 在bpo-32856中贡献。)

  • 优化了多线程应用程序中的信号处理。如果主线程以外的线程接收到信号,则字节码求值循环不再在每个字节码指令处中断以检查无法处理的待处理信号。只有主解释器的主线程才能处理信号。

    以前,字节码求值循环会在每个指令处中断,直到主线程处理信号。(由 Victor Stinner 在bpo-40010中贡献。)

  • 优化了在 FreeBSD 上使用 closefrom()subprocess 模块。(由 Ed Maste、Conrad Meyer、Kyle Evans、Kubilay Kocak 和 Victor Stinner 在bpo-38061中贡献。)

  • PyLong_FromDouble() 对于适合 long 的值现在速度提高了 1.87 倍。(由 Sergey Fedoseev 在bpo-37986中贡献。)

  • 许多 Python 内置函数(rangetuplesetfrozensetlistdict)现在通过使用 PEP 590 vectorcall 协议加速。(由 Donghee Na、Mark Shannon、Jeroen Demeyer 和 Petr Viktorin 在bpo-37207中贡献。)

  • 当其他集合远大于基础集合时,优化了 set.difference_update()。(由 Evgeny Kapun 建议,Michele Orrù 在bpo-8425中贡献代码。)

  • Python 的小对象分配器(obmalloc.c)现在允许(不多于)一个空竞技场保持可用以立即重用,而无需将其返回给操作系统。这可以防止在简单循环中出现抖动,因为在每次迭代中都会创建和销毁一个新的竞技场。(由 Tim Peters 在bpo-37257中贡献。)

  • 浮点数的向下取整除法操作现在具有更好的性能。此外,此操作的 ZeroDivisionError 消息也已更新。(由 Donghee Na 在bpo-39434中贡献。)

  • 使用 UTF-8 和 ascii 编码解码短 ASCII 字符串现在快了大约 15%。(由 Inada Naoki 在bpo-37348中贡献。)

以下是 Python 3.4 到 Python 3.9 的性能改进总结

Python version                       3.4     3.5     3.6     3.7     3.8    3.9
--------------                       ---     ---     ---     ---     ---    ---

Variable and attribute read access:
    read_local                       7.1     7.1     5.4     5.1     3.9    3.9
    read_nonlocal                    7.1     8.1     5.8     5.4     4.4    4.5
    read_global                     15.5    19.0    14.3    13.6     7.6    7.8
    read_builtin                    21.1    21.6    18.5    19.0     7.5    7.8
    read_classvar_from_class        25.6    26.5    20.7    19.5    18.4   17.9
    read_classvar_from_instance     22.8    23.5    18.8    17.1    16.4   16.9
    read_instancevar                32.4    33.1    28.0    26.3    25.4   25.3
    read_instancevar_slots          27.8    31.3    20.8    20.8    20.2   20.5
    read_namedtuple                 73.8    57.5    45.0    46.8    18.4   18.7
    read_boundmethod                37.6    37.9    29.6    26.9    27.7   41.1

Variable and attribute write access:
    write_local                      8.7     9.3     5.5     5.3     4.3    4.3
    write_nonlocal                  10.5    11.1     5.6     5.5     4.7    4.8
    write_global                    19.7    21.2    18.0    18.0    15.8   16.7
    write_classvar                  92.9    96.0   104.6   102.1    39.2   39.8
    write_instancevar               44.6    45.8    40.0    38.9    35.5   37.4
    write_instancevar_slots         35.6    36.1    27.3    26.6    25.7   25.8

Data structure read access:
    read_list                       24.2    24.5    20.8    20.8    19.0   19.5
    read_deque                      24.7    25.5    20.2    20.6    19.8   20.2
    read_dict                       24.3    25.7    22.3    23.0    21.0   22.4
    read_strdict                    22.6    24.3    19.5    21.2    18.9   21.5

Data structure write access:
    write_list                      27.1    28.5    22.5    21.6    20.0   20.0
    write_deque                     28.7    30.1    22.7    21.8    23.5   21.7
    write_dict                      31.4    33.3    29.3    29.2    24.7   25.4
    write_strdict                   28.4    29.9    27.5    25.2    23.1   24.5

Stack (or queue) operations:
    list_append_pop                 93.4   112.7    75.4    74.2    50.8   50.6
    deque_append_pop                43.5    57.0    49.4    49.2    42.5   44.2
    deque_append_popleft            43.7    57.3    49.7    49.7    42.8   46.4

Timing loop:
    loop_overhead                    0.5     0.6     0.4     0.3     0.3    0.3

这些结果是从以下可变访问基准脚本生成的:Tools/scripts/var_access_benchmark.py。该基准脚本以纳秒显示时间。基准测试是在运行 python.org 上 macOS 64 位构建的 Intel® Core™ i7-4960HQ 处理器上测量的。

已弃用

  • distutils bdist_msi 命令现在已弃用,请改用 bdist_wheel(wheel 包)。(由 Hugo van Kemenade 在bpo-39586中贡献。)

  • 目前 math.factorial() 接受具有非负整数值的 float 实例(例如 5.0)。对于非整数和负浮点数,它会引发 ValueError。此功能现已弃用。在未来的 Python 版本中,它将对所有浮点数引发 TypeError。(由 Serhiy Storchaka 在 bpo-37315 中贡献。)

  • parsersymbol 模块已弃用,并将在未来版本的 Python 中移除。对于大多数用例,用户可以使用 ast 模块,利用抽象语法树 (AST) 生成和编译阶段。

  • 公共 C API 函数 PyParser_SimpleParseStringFlags()PyParser_SimpleParseStringFlagsFilename()PyParser_SimpleParseFileFlags()PyNode_Compile() 已弃用,并将在 Python 3.10 中与旧解析器一起移除。

  • 在布尔上下文中使用 NotImplemented 已弃用,因为它几乎都是不正确的富比较器实现的结果。在未来的 Python 版本中,它将变为 TypeError。(由 Josh Rosenberg 在 bpo-35712 中贡献。)

  • random 模块目前接受任何可哈希类型作为可能的种子值。不幸的是,其中一些类型不保证具有确定性的哈希值。Python 3.9 之后,该模块将限制其种子为 Noneintfloatstrbytesbytearray

  • 在未指定 mode 参数的情况下打开 GzipFile 文件进行写入已弃用。在未来的 Python 版本中,它将默认始终以读取模式打开。请指定 mode 参数以写入方式打开并消除警告。(由 Serhiy Storchaka 在 bpo-28286 中贡献。)

  • _tkinter.TkappTypesplit() 方法已弃用,转而使用行为更一致和可预测的 splitlist() 方法。(由 Serhiy Storchaka 在 bpo-38371 中贡献。)

  • 将协程对象显式传递给 asyncio.wait() 已弃用,并将在 3.11 版本中移除。(由 Yury Selivanov 和 Kyle Stanley 在 bpo-34790 中贡献。)

  • binhex4 和 hexbin4 标准现已弃用。 binhex 模块和以下 binascii 函数现已弃用

    • b2a_hqx(), a2b_hqx()

    • rlecode_hqx(), rledecode_hqx()

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

  • astsliceIndexExtSlice 被视为已弃用,并将在未来的 Python 版本中移除。value 本身应替代 Index(value)Tuple(slices, Load()) 应替代 ExtSlice(slices)。(由 Serhiy Storchaka 在 bpo-34822 中贡献。)

  • astSuiteParamAugLoadAugStore 被视为已弃用,并将在未来的 Python 版本中移除。它们在 Python 3 中未由解析器生成,也未被代码生成器接受。(由 Batuhan Taskaya 在 bpo-39639bpo-39969 中贡献,由 Serhiy Storchaka 在 bpo-39988 中贡献。)

  • PyEval_InitThreads()PyEval_ThreadsInitialized() 函数现已弃用,并将在 Python 3.11 中移除。现在调用 PyEval_InitThreads() 不执行任何操作。GIL 自 Python 3.7 起由 Py_Initialize() 初始化。(由 Victor Stinner 在 bpo-39877 中贡献。)

  • None 作为第一个参数传递给 shlex.split() 函数已弃用。(由 Zackery Spytz 在 bpo-33262 中贡献。)

  • smtpd.MailmanProxy() 现已弃用,因为它在没有外部模块 mailman 的情况下无法使用。(由 Samuel Colvin 在 bpo-35800 中贡献。)

  • lib2to3 模块现在发出 PendingDeprecationWarning。Python 3.9 切换到 PEG 解析器(参见 PEP 617),Python 3.10 可能包含 lib2to3 的 LL(1) 解析器无法解析的新语言语法。 lib2to3 模块可能会在未来的 Python 版本中从标准库中移除。考虑第三方替代方案,例如 LibCSTparso。(由 Carl Meyer 在 bpo-40360 中贡献。)

  • random.shuffle()random 参数已弃用。(由 Raymond Hettinger 在 bpo-40465 中贡献)

已移除

  • unittest.mock.__version__ 中的错误版本已移除。

  • nntplib.NNTP: xpath()xgtitle() 方法已移除。这些方法自 Python 3.3 起已弃用。通常,NNTP 服务器管理员不支持或不启用这些扩展。对于 xgtitle(),请改用 nntplib.NNTP.descriptions()nntplib.NNTP.description()。(由 Donghee Na 在 bpo-39366 中贡献。)

  • array.array: tostring()fromstring() 方法已移除。它们是 tobytes()frombytes() 的别名,自 Python 3.2 起已弃用。(由 Victor Stinner 在 bpo-38916 中贡献。)

  • 未文档化的 sys.callstats() 函数已移除。自 Python 3.7 起,它已弃用并始终返回 None。它需要一个特殊构建选项 CALL_PROFILE,该选项在 Python 3.7 中已移除。(由 Victor Stinner 在 bpo-37414 中贡献。)

  • sys.getcheckinterval()sys.setcheckinterval() 函数已移除。它们自 Python 3.2 起已弃用。请改用 sys.getswitchinterval()sys.setswitchinterval()。(由 Victor Stinner 在 bpo-37392 中贡献。)

  • C 函数 PyImport_Cleanup() 已移除。它被记录为:“清空模块表。仅供内部使用。”(由 Victor Stinner 在 bpo-36710 中贡献。)

  • _dummy_threaddummy_threading 模块已移除。这些模块自 Python 3.7 起已弃用,因为它需要线程支持。(由 Victor Stinner 在 bpo-37312 中贡献。)

  • aifc.openfp()aifc.open() 的别名)、sunau.openfp()sunau.open() 的别名)和 wave.openfp()wave.open() 的别名)已移除。它们自 Python 3.7 起已弃用。(由 Victor Stinner 在 bpo-37320 中贡献。)

  • threading.ThreadisAlive() 方法已移除。它自 Python 3.8 起已弃用。请改用 is_alive()。(由 Donghee Na 在 bpo-37804 中贡献。)

  • ElementTree 模块中 ElementTreeElement 类的 getchildren()getiterator() 方法已移除。它们在 Python 3.2 中已弃用。请使用 iter(x)list(x) 代替 x.getchildren(),并使用 x.iter()list(x.iter()) 代替 x.getiterator()。(由 Serhiy Storchaka 在 bpo-36543 中贡献。)

  • 旧的 plistlib API 已移除,它自 Python 3.4 起已弃用。请使用 load()loads()dump()dumps() 函数。此外, use_builtin_types 参数已移除,始终使用标准 bytes 对象代替。(由 Jon Janzen 在 bpo-36409 中贡献。)

  • C 函数 PyGen_NeedsFinalizing 已移除。在实现 PEP 442 后,它在 CPython 中未被文档化、测试或使用。由 Joannah Nanjekye 提交补丁。(由 Joannah Nanjekye 在 bpo-15088 中贡献)

  • base64.encodestring()base64.decodestring()(自 Python 3.1 起弃用的别名)已移除:请改用 base64.encodebytes()base64.decodebytes()。(由 Victor Stinner 在 bpo-39351 中贡献。)

  • fractions.gcd() 函数已移除,它自 Python 3.5 起已弃用(bpo-22486):请改用 math.gcd()。(由 Victor Stinner 在 bpo-39350 中贡献。)

  • bz2.BZ2Filebuffering 参数已移除。自 Python 3.0 起,它被忽略,并且使用它会发出 DeprecationWarning。请传递一个已打开的文件对象来控制文件的打开方式。(由 Victor Stinner 在 bpo-39357 中贡献。)

  • json.loads()encoding 参数已移除。自 Python 3.1 起,它已弃用并被忽略;自 Python 3.8 起,使用它会发出 DeprecationWarning。(由 Inada Naoki 在 bpo-39377 中贡献)

  • with (await asyncio.lock):with (yield from asyncio.lock): 语句不再受支持,请改用 async with lockasyncio.Conditionasyncio.Semaphore 也是如此。(由 Andrew Svetlov 在 bpo-34793 中贡献。)

  • sys.getcounts() 函数、 -X showalloccount 命令行选项以及 C 结构 PyConfigshow_alloc_count 字段已移除。它们需要通过定义 COUNT_ALLOCS 宏的特殊 Python 构建。(由 Victor Stinner 在 bpo-39489 中贡献。)

  • typing.NamedTuple 类的 _field_types 属性已移除。它自 Python 3.8 起已弃用。请改用 __annotations__ 属性。(由 Serhiy Storchaka 在 bpo-40182 中贡献。)

  • symtable.SymbolTable.has_exec() 方法已移除。它自 2006 年起已弃用,并且在调用时仅返回 False。(由 Batuhan Taskaya 在 bpo-40208 中贡献)

  • asyncio.Task.current_task()asyncio.Task.all_tasks() 已移除。它们自 Python 3.7 起已弃用,您可以使用 asyncio.current_task()asyncio.all_tasks() 代替。(由 Rémi Lapeyre 在 bpo-40967 中贡献)

  • html.parser.HTMLParser 类中的 unescape() 方法已移除(它自 Python 3.4 起已弃用)。应使用 html.unescape() 将字符引用转换为相应的 Unicode 字符。

移植到 Python 3.9

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

Python API 的变化

  • __import__()importlib.util.resolve_name() 现在在以前引发 ValueError 的地方引发 ImportError。调用方捕获特定异常类型并支持 Python 3.9 及更早版本时,需要使用 except (ImportError, ValueError): 同时捕获两者。

  • __VENV_PROMPT__ 设置为 "" 时, venv 激活脚本不再进行特殊处理。

  • select.epoll.unregister() 方法不再忽略 EBADF 错误。(由 Victor Stinner 在 bpo-39239 中贡献。)

  • bz2.BZ2Filecompresslevel 参数变为仅关键字参数,因为 buffering 参数已移除。(由 Victor Stinner 在 bpo-39357 中贡献。)

  • 简化的 AST 用于订阅。简单索引将由其值表示,扩展切片将表示为元组。Index(value) 将返回 value 本身,ExtSlice(slices) 将返回 Tuple(slices, Load())。(由 Serhiy Storchaka 在 bpo-34822 中贡献。)

  • 当使用 -E-I 命令行选项时, importlib 模块现在会忽略 PYTHONCASEOK 环境变量。

  • encoding 参数已作为仅关键字参数添加到 ftplib.FTPftplib.FTP_TLS 类中,并且默认编码已从 Latin-1 更改为 UTF-8,以遵循 RFC 2640

  • asyncio.loop.shutdown_default_executor() 已添加到 AbstractEventLoop,这意味着继承自它的替代事件循环应该定义此方法。(由 Kyle Stanley 在 bpo-34037 中贡献。)

  • __future__ 模块中未来标志的常量值已更新,以防止与编译器标志冲突。以前 PyCF_ALLOW_TOP_LEVEL_AWAITCO_FUTURE_DIVISION 冲突。(由 Batuhan Taskaya 在 bpo-39562 中贡献)

  • array('u') 现在使用 wchar_t 作为 C 类型,而不是 Py_UNICODE。此更改不影响其行为,因为 Py_UNICODE 自 Python 3.3 起就是 wchar_t 的别名。(由 Inada Naoki 在 bpo-34538 中贡献。)

  • 当传递名称 'root' 时, logging.getLogger() API 现在返回根日志器,而以前它返回一个名为 'root' 的非根日志器。这可能会影响用户代码明确需要名为 'root' 的非根日志器的情况,或者在名为 'root.py' 的某个顶级模块中使用 logging.getLogger(__name__) 实例化日志器的情况。(由 Vinay Sajip 在 bpo-37742 中贡献。)

  • 当传递不是 strPurePath 实例的对象时, PurePath 的除法处理现在返回 NotImplemented,而不是引发 TypeError。这允许创建不继承自上述类型的兼容类。(由 Roger Aiudi 在 bpo-34775 中贡献)。

  • 从 Python 3.9.5 开始, ipaddress 模块不再接受 IPv4 地址字符串中的任何前导零。前导零是模糊的,并且被某些库解释为八进制表示法。例如,旧函数 socket.inet_aton() 将前导零视为八进制表示法。glibc 实现的现代 inet_pton() 不接受任何前导零。(由 Christian Heimes 在 bpo-36384 中贡献)。

  • codecs.lookup() 现在以与 encodings.normalize_encoding() 相同的方式规范化编码名称,只是 codecs.lookup() 还会将名称转换为小写。例如, "latex+latin1" 编码名称现在规范化为 "latex_latin1"。(由 Jordon Xu 在 bpo-37751 中贡献。)

C API 的变化

  • 自 Python 3.8 起, 堆分配类型 的实例(例如使用 PyType_FromSpec() 和类似 API 创建的实例)持有对其类型对象的引用。如 Python 3.8 的“C API 变更”中所述,对于绝大多数情况,不应有副作用,但对于具有自定义 tp_traverse 函数的类型,请确保堆分配类型的所有自定义 tp_traverse 函数都访问对象的类型。

    示例

    int
    foo_traverse(PyObject *self, visitproc visit, void *arg)
    {
    // Rest of the traverse function
    #if PY_VERSION_HEX >= 0x03090000
        // This was not needed before Python 3.9 (Python issue 35810 and 40217)
        Py_VISIT(Py_TYPE(self));
    #endif
    }
    

    如果您的遍历函数委托给其基类(或其他类型)的 tp_traverse,请确保 Py_TYPE(self) 仅被访问一次。请注意,只有 堆类型 预期会在 tp_traverse 中访问类型。

    例如,如果您的 tp_traverse 函数包含

    base->tp_traverse(self, visit, arg)
    

    然后添加

    #if PY_VERSION_HEX >= 0x03090000
        // This was not needed before Python 3.9 (bpo-35810 and bpo-40217)
        if (base->tp_flags & Py_TPFLAGS_HEAPTYPE) {
            // a heap type's tp_traverse already visited Py_TYPE(self)
        } else {
            Py_VISIT(Py_TYPE(self));
        }
    #else
    

    (有关更多信息,请参见 bpo-35810bpo-40217。)

  • 函数 PyEval_CallObjectPyEval_CallFunctionPyEval_CallMethodPyEval_CallObjectWithKeywords 已弃用。请改用 PyObject_Call() 及其变体。(更多详细信息请参见 bpo-29548。)

CPython 字节码变更

  • 添加了 LOAD_ASSERTION_ERROR 操作码,用于处理 assert 语句。以前,如果 AssertionError 异常被遮蔽,断言语句将无法正常工作。(由 Zackery Spytz 在 bpo-34880 中贡献。)

  • COMPARE_OP 操作码已拆分为四个不同的指令

    • 用于富比较的 COMPARE_OP

    • 用于“is”和“is not”测试的 IS_OP

    • 用于“in”和“not in”测试的 CONTAINS_OP

    • 用于在“try-except”语句中检查异常的 JUMP_IF_NOT_EXC_MATCH

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

构建更改

  • configure 脚本添加了 --with-platlibdir 选项:平台特定库目录的名称,存储在新的 sys.platlibdir 属性中。有关更多信息,请参见 sys.platlibdir 属性。(由 Jan Matějek, Matěj Cepl, Charalampos Stratakis 和 Victor Stinner 在 bpo-1294959 中贡献。)

  • COUNT_ALLOCS 特殊构建宏已移除。(由 Victor Stinner 在 bpo-39489 中贡献。)

  • 在非 Windows 平台上,现在需要 setenv()unsetenv() 函数才能构建 Python。(由 Victor Stinner 在 bpo-39395 中贡献。)

  • 在非 Windows 平台上,创建 bdist_wininst 安装程序现已正式不支持。(有关更多详细信息,请参见 bpo-10945。)

  • 从源代码在 macOS 上构建 Python 时,如果非系统 Tcl 和 Tk 框架安装在 /Library/Frameworks 中, _tkinter 现在会链接它们,就像在旧版 macOS 上一样。如果通过使用 --enable-universalsdk-isysroot 显式配置 macOS SDK,则只搜索 SDK 本身。默认行为仍可通过 --with-tcltk-includes--with-tcltk-libs 覆盖。(由 Ned Deily 在 bpo-34956 中贡献。)

  • Python 现在可以为 Windows 10 ARM64 构建。(由 Steve Dower 在 bpo-33125 中贡献。)

  • 现在在使用 --pgo 时会跳过某些单独的测试。所涉及的测试显著增加了 PGO 任务时间,并且可能无助于改进最终可执行文件的优化。这使得任务速度提高了大约 15 倍。运行完整的单元测试套件很慢。此更改可能导致构建优化程度略低,因为执行的代码分支不会那么多。如果您愿意等待更慢的构建,可以使用 ./configure [..] PROFILE_TASK="-m test --pgo-extended" 恢复旧行为。我们不保证哪个 PGO 任务集能产生更快的构建。关注此问题的用户应运行自己的相关基准测试,因为结果可能取决于环境、工作负载和编译器工具链。(有关更多详细信息,请参见 bpo-36044bpo-37707。)

C API 更改

新特性

移植到 Python 3.9

  • PyInterpreterState.eval_framePEP 523)现在需要一个新的强制性 tstate 参数(PyThreadState*)。(由 Victor Stinner 在 bpo-38500 中贡献。)

  • 扩展模块:如果请求了模块状态但尚未分配,则不再调用 m_traversem_clearm_freePyModuleDef 函数。这发生在模块创建后立即以及模块执行之前(Py_mod_exec 函数)。更准确地说,如果 m_size 大于 0 且模块状态(由 PyModule_GetState() 返回)为 NULL,则不调用这些函数。

    没有模块状态的扩展模块(m_size <= 0)不受影响。

  • 如果在子解释器中调用 Py_AddPendingCall(),现在该函数计划从子解释器而不是主解释器调用。每个子解释器现在都有自己的计划调用列表。(由 Victor Stinner 在 bpo-39984 中贡献。)

  • 当使用 -E 选项时(如果 PyConfig.use_environment 设置为 0),Windows 注册表不再用于初始化 sys.path。这在 Windows 上嵌入 Python 时非常重要。(由 Zackery Spytz 在 bpo-8901 中贡献。)

  • 全局变量 PyStructSequence_UnnamedField 现在是一个常量,并引用一个常量字符串。(由 Serhiy Storchaka 在 bpo-38650 中贡献。)

  • PyGC_Head 结构现在是不透明的。它仅在内部 C API(pycore_gc.h)中定义。(由 Victor Stinner 在 bpo-40241 中贡献。)

  • Py_UNICODE_COPY, Py_UNICODE_FILL, PyUnicode_WSTR_LENGTH, PyUnicode_FromUnicode(), PyUnicode_AsUnicode(), _PyUnicode_AsUnicodePyUnicode_AsUnicodeAndSize() 在 C 中被标记为已弃用。它们自 Python 3.3 起已被 PEP 393 弃用。(由 Inada Naoki 在 bpo-36346 中贡献。)

  • Py_FatalError() 函数被宏替换,除非定义了 Py_LIMITED_API 宏,否则该宏会自动记录当前函数的名称。(由 Victor Stinner 在 bpo-39882 中贡献。)

  • vectorcall 协议现在要求调用者只将字符串作为关键字名称传递。(有关更多信息,请参见 bpo-37540。)

  • 许多宏和函数的实现细节现在被隐藏

    (有关更多详细信息,请参见 bpo-40170。)

已移除

  • pyfpe.h 中的 PyFPE_START_PROTECT()PyFPE_END_PROTECT() 宏从受限 C API 中排除。(由 Victor Stinner 在 bpo-38835 中贡献。)

  • PyTypeObjecttp_print 槽已移除。它在 Python 2.7 及更早版本中用于将对象打印到文件。自 Python 3.0 起,它已被忽略和未使用。(由 Jeroen Demeyer 在 bpo-36974 中贡献。)

  • 受限 C API 中的更改(如果定义了 Py_LIMITED_API 宏)

    • 从受限 C API 中排除了以下函数

      • PyThreadState_DeleteCurrent() (由 Joannah Nanjekye 在 bpo-37878 中贡献。)

      • _Py_CheckRecursionLimit

      • _Py_NewReference()

      • _Py_ForgetReference()

      • _PyTraceMalloc_NewReference()

      • _Py_GetRefTotal()

      • 在受限 C API 中从未起作用的垃圾桶机制。

      • PyTrash_UNWIND_LEVEL

      • Py_TRASHCAN_BEGIN_CONDITION

      • Py_TRASHCAN_BEGIN

      • Py_TRASHCAN_END

      • Py_TRASHCAN_SAFE_BEGIN

      • Py_TRASHCAN_SAFE_END

    • 将以下函数和定义移至内部 C API

      • _PyDebug_PrintTotalRefs()

      • _Py_PrintReferences()

      • _Py_PrintReferenceAddresses()

      • _Py_tracemalloc_config

      • _Py_AddToAllObjects() (特定于 Py_TRACE_REFS 构建)

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

  • 移除了 _PyRuntime.getframe 钩子,并移除了 _PyThreadState_GetFrame 宏,该宏是 _PyRuntime.getframe 的别名。它们仅由内部 C API 公开。还移除了 PyThreadFrameGetter 类型。(由 Victor Stinner 在 bpo-39946 中贡献。)

  • 从 C API 中移除了以下函数。明确调用 PyGC_Collect() 以清除所有空闲列表。(由 Inada Naoki 和 Victor Stinner 在 bpo-37340bpo-38896bpo-40428 中贡献。)

    • PyAsyncGen_ClearFreeLists()

    • PyContext_ClearFreeList()

    • PyDict_ClearFreeList()

    • PyFloat_ClearFreeList()

    • PyFrame_ClearFreeList()

    • PyList_ClearFreeList()

    • PyMethod_ClearFreeList()PyCFunction_ClearFreeList():绑定的方法对象的空闲列表已移除。

    • PySet_ClearFreeList():集合空闲列表已在 Python 3.4 中移除。

    • PyTuple_ClearFreeList()

    • PyUnicode_ClearFreeList():Unicode 空闲列表已在 Python 3.3 中移除。

  • 移除了 _PyUnicode_ClearStaticStrings() 函数。(由 Victor Stinner 在 bpo-39465 中贡献。)

  • 移除了 Py_UNICODE_MATCH。它已被 PEP 393 弃用,并且自 Python 3.3 起已失效。可以改用 PyUnicode_Tailmatch() 函数。(由 Inada Naoki 在 bpo-36346 中贡献。)

  • 清理了已定义但没有实现的接口头文件。移除的公共 API 符号有:_PyBytes_InsertThousandsGroupingLocale_PyBytes_InsertThousandsGrouping_Py_InitializeFromArgs_Py_InitializeFromWideArgs_PyFloat_Repr_PyFloat_Digits_PyFloat_DigitsInitPyFrame_ExtendStack_PyAIterWrapper_TypePyNullImporter_TypePyCmpWrapper_TypePySortWrapper_TypePyNoArgsFunction。(由 Pablo Galindo Salgado 在 bpo-39372 中贡献。)

Python 3.9.1 中的显著更改

类型提示

typing.Literal 的行为已更改,以符合 PEP 586 并与 PEP 中指定的静态类型检查器的行为匹配。

  1. Literal 现在会删除重复的参数。

  2. Literal 对象之间的相等比较现在与顺序无关。

  3. Literal 比较现在遵循类型。例如, Literal[0] == Literal[False] 以前评估为 True。现在是 False。为了支持这一变化,内部使用的类型缓存现在支持区分类型。

  4. 如果 Literal 对象的任何参数不是 可哈希的,它们现在将在相等比较期间引发 TypeError 异常。请注意,使用可变参数声明 Literal 不会引发错误

    >>> from typing import Literal
    >>> Literal[{0}]
    >>> Literal[{0}] == Literal[{False}]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unhashable type: 'set'
    

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

macOS 11.0 (Big Sur) 和 Apple Silicon Mac 支持

自 3.9.1 版起,Python 现在完全支持在 macOS 11.0 (Big Sur) 和 Apple Silicon Mac(基于 ARM64 架构)上构建和运行。新的通用构建变体 universal2 现已推出,可在一个可执行文件集中原生支持 ARM64Intel 64。现在还可以在当前版本的 macOS 上构建二进制文件,以部署到一系列旧版 macOS 版本(测试到 10.9),同时根据运行时使用的操作系统版本有条件地提供一些较新的 OS 功能和选项(“弱链接”)。

(由 Ronald Oussoren 和 Lawrence D’Anna 在 bpo-41100 中贡献。)

Python 3.9.2 中的显著更改

collections.abc

collections.abc.Callable 泛型现在会扁平化类型参数,类似于 typing.Callable 当前的做法。这意味着 collections.abc.Callable[[int, str], str]__args__ 将是 (int, str, str);以前是 ([int, str], str)。为了允许此更改, types.GenericAlias 现在可以被子类化,并且在对 collections.abc.Callable 类型进行下标操作时将返回一个子类。通过 typing.get_args()__args__ 访问参数的代码需要考虑此更改。对于参数化 collections.abc.Callable 的无效形式,可能会发出 DeprecationWarning,这些形式在 Python 3.9.1 中可能悄无声息地通过。此 DeprecationWarning 将在 Python 3.10 中变为 TypeError。(由 Ken Jin 在 bpo-42195 中贡献。)

urllib.parse

早期的 Python 版本允许在 urllib.parse.parse_qs()urllib.parse.parse_qsl() 中使用 ;& 作为查询参数分隔符。出于安全考虑,并为了符合新的 W3C 建议,此功能已更改为只允许一个分隔符键,默认值为 &。此更改也影响 cgi.parse()cgi.parse_multipart(),因为它们内部使用了受影响的函数。有关更多详细信息,请参见其各自的文档。(由 Adam Goldschmidt、Senthil Kumaran 和 Ken Jin 在 bpo-42967 中贡献。)

Python 3.9.3 中的显著更改

一项安全修复程序改变了 ftplib.FTP 的行为,使其在建立被动数据通道时不再信任远程服务器发送的 IPv4 地址。我们改为重用 FTP 服务器的 IP 地址。对于需要旧行为的特殊代码,请将 FTP 实例上的 trust_server_pasv_ipv4_address 属性设置为 True。(参见 gh-87451)

Python 3.9.5 中的显著更改

urllib.parse

URL 部分中存在换行符或制表符字符可能导致某些形式的攻击。根据更新 RFC 3986 的 WHATWG 规范, urllib.parse 中的解析器会从 URL 中去除 ASCII 换行符 \n\r 和制表符 \t 字符,从而防止此类攻击。删除的字符由新的模块级变量 urllib.parse._UNSAFE_URL_BYTES_TO_REMOVE 控制。(请参见 gh-88048

3.9.14 中的显著安全特性

在将数字转换为其他进制(如十进制)时,如果字符串形式的位数超过限制,则会引发 ValueError,以避免因算法复杂性而导致的潜在拒绝服务攻击。此限制适用于除了 2(二进制)、4、8(八进制)、16(十六进制)或 32 以外的进制。这是针对 CVE 2020-10735 的缓解措施。此限制可以通过环境变量、命令行标志或 sys API 进行配置或禁用。有关详细信息,请参阅整数字符串转换长度限制文档。默认限制是字符串形式的 4300 位。

3.9.17 中的显著变化

tarfile

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