Python 3.9 中的新特性¶
- 编辑:
Łukasz Langa
本文解释了 Python 3.9 相较于 3.8 的新特性。Python 3.9 于 2020 年 10 月 5 日发布。有关完整详细信息,请参阅更新日志。
参见
PEP 596 - Python 3.9 发布时间表
摘要 – 发布亮点¶
新语法功能
新的内置功能
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 模块(
_abc、audioop、_bz2、_codecs、_contextvars、_crypt、_functools、_json、_locale、math、operator、resource、time、_weakref)现在使用 PEP 489 定义的多阶段初始化;许多标准库模块(
audioop、ast、grp、_hashlib、pwd、_posixsubprocess、random、select、struct、termios、zlib)现在使用 PEP 384 定义的稳定 ABI。
新库模块
发布过程变更
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 命令行选项测试您的应用程序,以查看 DeprecationWarning 和 PendingDeprecationWarning,甚至可以使用 -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'}
新的字符串方法,用于删除前缀和后缀¶
已添加 str.removeprefix(prefix) 和 str.removesuffix(suffix),以便轻松从字符串中删除不需要的前缀或后缀。相应的 bytes、bytearray 和 collections.UserString 方法也已添加。有关完整说明,请参阅PEP 616。(由 Dennis Sweeney 在bpo-39939中贡献。)
标准集合中的类型提示泛型¶
在类型注解中,您现在可以使用内置的集合类型,例如 list 和 dict 作为泛型类型,而不是从 typing 中导入相应的首字母大写的类型(例如 List 或 Dict)。标准库中的其他一些类型现在也是泛型的,例如 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 开发模式和调试构建中,现在会检查字符串编码和解码操作的 encoding 和 errors 参数。例如:
open()、str.encode()和bytes.decode()。默认情况下,为了获得最佳性能,仅在第一次编码/解码错误时检查 errors 参数,并且有时会忽略空字符串的 encoding 参数。(由 Victor Stinner 在bpo-37388中贡献。)
"".replace("", s, n)现在对于所有非零n返回s而不是空字符串。它现在与"".replace("", s)一致。bytes和bytearray对象也有类似的更改。(由 Serhiy Storchaka 在bpo-28029中贡献。)任何有效的表达式现在都可以用作装饰器。以前,语法更加严格。有关详细信息,请参阅PEP 614。(由 Brandt Bucher 在bpo-39702中贡献。)
改进了
typing模块的帮助。现在为所有特殊形式和特殊泛型别名(如Union和List)显示 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-41848 和 bpo-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 文件中进行路径操作的新选项:stripdir、prependdir、limit_sl_dest 参数以及 -s、-p、-e 命令行选项。添加了多次指定优化级别选项的可能性。(由 Lumír ‘Frenzy’ Balhar 在bpo-38112中贡献。)
concurrent.futures¶
向 concurrent.futures.Executor.shutdown() 添加了一个新的 cancel_futures 参数,该参数取消所有尚未开始运行的待处理 future,而不是等待它们完成才关闭执行器。(由 Kyle Stanley 在bpo-39349中贡献。)
从 ThreadPoolExecutor 和 ProcessPoolExecutor 中移除了守护线程。这改善了与子解释器的兼容性以及其关闭过程的可预测性。(由 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.date 的 isocalendar() 方法和 datetime.datetime 的 isocalendar() 方法现在返回 namedtuple() 而不是 tuple。(由 Donghee Na 在bpo-24416中贡献。)
distutils¶
upload 命令现在创建 SHA2-256 和 Blake2b-256 哈希摘要。它在阻止 MD5 摘要的平台上跳过 MD5。(由 Christian Heimes 在bpo-40698中贡献。)
fcntl¶
添加了常量 fcntl.F_OFD_GETLK、fcntl.F_OFD_SETLK 和 fcntl.F_OFD_SETLKW。(由 Donghee Na 在bpo-38602中贡献。)
ftplib¶
FTP 和 FTP_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_HINTS、418 IM_A_TEAPOT 和 425 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¶
IMAP4 和 IMAP4_SSL 的构造函数现在具有一个可选的 timeout 参数。此外,open() 方法现在也具有一个可选的 timeout 参数。此更改已应用于 IMAP4_SSL 和 IMAP4_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.arguments 从 OrderedDict 更改为普通 dict。(由 Inada Naoki 在bpo-36350和bpo-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-39479和bpo-39648中贡献。)
添加了 math.nextafter():返回 x 之后朝向 y 的下一个浮点值。(由 Victor Stinner 在bpo-39288中贡献。)
添加了 math.ulp():返回浮点数最低有效位的值。(由 Victor Stinner 在bpo-39310中贡献。)
multiprocessing¶
multiprocessing.SimpleQueue 类有一个新的 close() 方法,用于显式关闭队列。(由 Victor Stinner 在bpo-30966中贡献。)
nntplib¶
NNTP 和 NNTP_SSL 现在,如果其构造函数给定的超时为零,则会引发 ValueError,以防止创建非阻塞套接字。(由 Donghee Na 在bpo-39259中贡献。)
os¶
为 si_code 添加了 CLD_KILLED 和 CLD_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¶
POP3 和 POP3_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¶
SMTP 和 SMTP_SSL 现在,如果其构造函数给定的超时为零,则会引发 ValueError,以防止创建非阻塞套接字。(由 Donghee Na 在bpo-39259中贡献。)
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 内置函数(
range、tuple、set、frozenset、list、dict)现在通过使用 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 中贡献。)parser和symbol模块已弃用,并将在未来版本的 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 之后,该模块将限制其种子为None、int、float、str、bytes和bytearray。在未指定 mode 参数的情况下打开
GzipFile文件进行写入已弃用。在未来的 Python 版本中,它将默认始终以读取模式打开。请指定 mode 参数以写入方式打开并消除警告。(由 Serhiy Storchaka 在 bpo-28286 中贡献。)_tkinter.TkappType的split()方法已弃用,转而使用行为更一致和可预测的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 中贡献。)
ast类slice、Index和ExtSlice被视为已弃用,并将在未来的 Python 版本中移除。value本身应替代Index(value)。Tuple(slices, Load())应替代ExtSlice(slices)。(由 Serhiy Storchaka 在 bpo-34822 中贡献。)ast类Suite、Param、AugLoad和AugStore被视为已弃用,并将在未来的 Python 版本中移除。它们在 Python 3 中未由解析器生成,也未被代码生成器接受。(由 Batuhan Taskaya 在 bpo-39639 和 bpo-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 版本中从标准库中移除。考虑第三方替代方案,例如 LibCST 或 parso。(由 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_thread和dummy_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.Thread的isAlive()方法已移除。它自 Python 3.8 起已弃用。请改用is_alive()。(由 Donghee Na 在 bpo-37804 中贡献。)ElementTree模块中ElementTree和Element类的getchildren()和getiterator()方法已移除。它们在 Python 3.2 中已弃用。请使用iter(x)或list(x)代替x.getchildren(),并使用x.iter()或list(x.iter())代替x.getiterator()。(由 Serhiy Storchaka 在 bpo-36543 中贡献。)旧的
plistlibAPI 已移除,它自 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.BZ2File的 buffering 参数已移除。自 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 lock。asyncio.Condition和asyncio.Semaphore也是如此。(由 Andrew Svetlov 在 bpo-34793 中贡献。)sys.getcounts()函数、-X showalloccount命令行选项以及 C 结构PyConfig的show_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.BZ2File的 compresslevel 参数变为仅关键字参数,因为 buffering 参数已移除。(由 Victor Stinner 在 bpo-39357 中贡献。)简化的 AST 用于订阅。简单索引将由其值表示,扩展切片将表示为元组。
Index(value)将返回value本身,ExtSlice(slices)将返回Tuple(slices, Load())。(由 Serhiy Storchaka 在 bpo-34822 中贡献。)当使用
-E或-I命令行选项时,importlib模块现在会忽略PYTHONCASEOK环境变量。encoding 参数已作为仅关键字参数添加到
ftplib.FTP和ftplib.FTP_TLS类中,并且默认编码已从 Latin-1 更改为 UTF-8,以遵循 RFC 2640。asyncio.loop.shutdown_default_executor()已添加到AbstractEventLoop,这意味着继承自它的替代事件循环应该定义此方法。(由 Kyle Stanley 在 bpo-34037 中贡献。)__future__模块中未来标志的常量值已更新,以防止与编译器标志冲突。以前PyCF_ALLOW_TOP_LEVEL_AWAIT与CO_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 中贡献。)当传递不是
str或PurePath实例的对象时,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
函数
PyEval_CallObject、PyEval_CallFunction、PyEval_CallMethod和PyEval_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-36044 和 bpo-37707。)
C API 更改¶
新特性¶
PEP 573:添加了
PyType_FromModuleAndSpec()以将模块与类关联;PyType_GetModule()和PyType_GetModuleState()以检索模块及其状态;以及PyCMethod和METH_METHOD以允许方法访问其定义的类。(由 Marcel Plch 和 Petr Viktorin 在 bpo-38787 中贡献。)添加了
PyFrame_GetCode()函数:获取帧代码。添加了PyFrame_GetBack()函数:获取帧的下一个外部帧。(由 Victor Stinner 在 bpo-40421 中贡献。)将
PyFrame_GetLineNumber()添加到受限 C API。(由 Victor Stinner 在 bpo-40421 中贡献。)添加了
PyThreadState_GetInterpreter()和PyInterpreterState_Get()函数以获取解释器。添加了PyThreadState_GetFrame()函数以获取 Python 线程状态的当前帧。添加了PyThreadState_GetID()函数:获取 Python 线程状态的唯一标识符。(由 Victor Stinner 在 bpo-39947 中贡献。)向 C API 添加了新的公共
PyObject_CallNoArgs()函数,该函数调用不带任何参数的可调用 Python 对象。它是调用不带任何参数的可调用 Python 对象的最有效方式。(由 Victor Stinner 在 bpo-37194 中贡献。)受限 C API 中的更改(如果定义了
Py_LIMITED_API宏)为受限 API 提供
Py_EnterRecursiveCall()和Py_LeaveRecursiveCall()作为常规函数。以前,它们被定义为宏,但这些宏在受限 C API 中无法编译,因为受限 C API 无法访问PyThreadState.recursion_depth字段(该结构在受限 C API 中是不透明的)。PyObject_INIT()和PyObject_INIT_VAR()成为常规的“不透明”函数,以隐藏实现细节。
添加了
PyModule_AddType()函数,以帮助将类型添加到模块。(由 Donghee Na 在 bpo-40024 中贡献。)添加了
PyObject_GC_IsTracked()和PyObject_GC_IsFinalized()函数到公共 API,以允许查询 Python 对象是否当前正在被垃圾回收器跟踪或是否已完成最终化。(由 Pablo Galindo Salgado 在 bpo-40241 中贡献。)添加了
_PyObject_FunctionStr()以获取函数类对象的友好字符串表示形式。(由 Jeroen Demeyer 在 bpo-37645 中提交补丁。)添加了
PyObject_CallOneArg()以使用一个位置参数调用对象(由 Jeroen Demeyer 在 bpo-37483 中提交补丁。)
移植到 Python 3.9¶
PyInterpreterState.eval_frame(PEP 523)现在需要一个新的强制性 tstate 参数(PyThreadState*)。(由 Victor Stinner 在 bpo-38500 中贡献。)扩展模块:如果请求了模块状态但尚未分配,则不再调用
m_traverse、m_clear和m_free的PyModuleDef函数。这发生在模块创建后立即以及模块执行之前(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_AsUnicode和PyUnicode_AsUnicodeAndSize()在 C 中被标记为已弃用。它们自 Python 3.3 起已被 PEP 393 弃用。(由 Inada Naoki 在 bpo-36346 中贡献。)Py_FatalError()函数被宏替换,除非定义了Py_LIMITED_API宏,否则该宏会自动记录当前函数的名称。(由 Victor Stinner 在 bpo-39882 中贡献。)vectorcall 协议现在要求调用者只将字符串作为关键字名称传递。(有关更多信息,请参见 bpo-37540。)
许多宏和函数的实现细节现在被隐藏
PyObject_IS_GC()宏已转换为函数。PyObject_NEW()宏成为PyObject_New宏的别名,PyObject_NEW_VAR()宏成为PyObject_NewVar宏的别名。它们不再直接访问PyTypeObject.tp_basicsize成员。PyObject_GET_WEAKREFS_LISTPTR()宏已转换为函数:该宏直接访问PyTypeObject.tp_weaklistoffset成员。PyObject_CheckBuffer()宏已转换为函数:该宏直接访问PyTypeObject.tp_as_buffer成员。PyIndex_Check()现在始终声明为不透明函数以隐藏实现细节:移除了PyIndex_Check()宏。该宏直接访问PyTypeObject.tp_as_number成员。
(有关更多详细信息,请参见 bpo-40170。)
已移除¶
将
pyfpe.h中的PyFPE_START_PROTECT()和PyFPE_END_PROTECT()宏从受限 C API 中排除。(由 Victor Stinner 在 bpo-38835 中贡献。)PyTypeObject 的
tp_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_LEVELPy_TRASHCAN_BEGIN_CONDITIONPy_TRASHCAN_BEGINPy_TRASHCAN_ENDPy_TRASHCAN_SAFE_BEGINPy_TRASHCAN_SAFE_END
将以下函数和定义移至内部 C API
_PyDebug_PrintTotalRefs()_Py_PrintReferences()_Py_PrintReferenceAddresses()_Py_tracemalloc_config_Py_AddToAllObjects()(特定于Py_TRACE_REFS构建)
移除了
_PyRuntime.getframe钩子,并移除了_PyThreadState_GetFrame宏,该宏是_PyRuntime.getframe的别名。它们仅由内部 C API 公开。还移除了PyThreadFrameGetter类型。(由 Victor Stinner 在 bpo-39946 中贡献。)从 C API 中移除了以下函数。明确调用
PyGC_Collect()以清除所有空闲列表。(由 Inada Naoki 和 Victor Stinner 在 bpo-37340、bpo-38896 和 bpo-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_DigitsInit、PyFrame_ExtendStack、_PyAIterWrapper_Type、PyNullImporter_Type、PyCmpWrapper_Type、PySortWrapper_Type、PyNoArgsFunction。(由 Pablo Galindo Salgado 在 bpo-39372 中贡献。)
Python 3.9.1 中的显著更改¶
类型提示¶
typing.Literal 的行为已更改,以符合 PEP 586 并与 PEP 中指定的静态类型检查器的行为匹配。
Literal现在会删除重复的参数。Literal对象之间的相等比较现在与顺序无关。Literal比较现在遵循类型。例如,Literal[0] == Literal[False]以前评估为True。现在是False。为了支持这一变化,内部使用的类型缓存现在支持区分类型。如果
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 现已推出,可在一个可执行文件集中原生支持 ARM64 和 Intel 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¶
tarfile和shutil.unpack_archive()中的提取方法新增了一个 filter 参数,允许限制可能令人意外或危险的 tar 功能,例如在目标目录之外创建文件。有关详细信息,请参阅 提取过滤器。在 Python 3.12 中,不带 filter 参数的使用将显示DeprecationWarning。在 Python 3.14 中,默认值将切换为'data'。(由 Petr Viktorin 在 PEP 706 中贡献。)