CPython 3.20 弃用前瞻:即将移除的 5 项语言与标准库特性及迁移指南

CPython 3.20 弃用前瞻:即将移除的 5 项语言与标准库特性及迁移指南 CPython 3.20 弃用前瞻即将移除的 5 项语言与标准库特性及迁移指南【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython本文基于 CPython 仓库中 Doc/deprecations/pending-removal-in-3.20.rst 官方弃用公告系统讲解将在 Python 3.20 中移除的五类特性struct.Struct构造函数行为、24 个标准库模块的__version__等版本属性、PEP 829 引入的.pth文件行为变化、抽象 AST 节点的直接实例化以及非显式runtime_checkable协议类的isinstance/issubclass检查。读完后你将掌握每一项弃用的确切语义、仓库中的源码级实现证据以及面向 3.20 的完整迁移方案。弃用公告机制为什么会有 pending-removal 文档CPython 的弃用流程通常分为“弃用deprecation发出DeprecationWarning”和“移除removal”两个阶段。Doc/deprecations/ 目录按目标版本归档了每一批待移除的特性pending-removal-in-3.20.rst记录的就是“当前开发版已经弃用、将在 3.20 正式移除”的条目。这意味着这些特性在 3.20 之前的版本中仍可用但会发出弃用警告升级路径应以该文件为清单逐项排查代码。一、struct.Struct禁止无 format 参数构造禁止重复初始化弃用内容公告原文包含两条相互关联的弃用由 Sergey B Kirpichev 和 Serhiy Storchaka 提交调用struct.Struct的__new__()方法时不传format参数已被弃用将在 3.20 移除对已初始化的Struct对象再次调用__init__()方法已被弃用将在 3.20 移除。源码实现证据Struct由 C 扩展实现核心构造逻辑位于 Modules/_struct.cs_new()约 L1883-L1950负责解析format参数。当未以“恰好一个位置参数”或“单个format关键字参数”形式提供 format且类没有自定义__init__覆盖时源码在 L1899-L1916 显式发出DeprecationWarning参数多于一个时Struct() takes at most 1 argument (N given)完全缺失时Struct() missing required argument format (pos 1)。重复初始化的弃用位于Struct___init___impl()约 L1980-L2003对象上维护了s_format与init_called两个状态位。若对象已持有 format 且再次以不同格式初始化会发出警告Re-initialization of Struct by calling the __init__() method will not work in future Python versionsL1989-L1996而s_init()L2005-L2019则在“__init__被解释器隐式调用、但__new__已完成全部工作”时直接短路返回避免重复处理。迁移方案正确的构造方式始终是一次性传入 format 字符串之后视其为不可变的编译产物import struct # 推荐构造时提供 format唯一可靠方式 s struct.Struct(I4d) data s.pack(1234, 1.5, 2.5, 3.5, 4.5) values s.unpack(data) # 不要依赖以下两种即将移除的行为 # 1. s2 struct.Struct() # 无 format 参数构造 # 2. s2 struct.Struct.__new__(struct.Struct) # 同上 # 3. 对已构造对象再次 s2.__init__(h) 重新初始化若确实需要“不同格式”直接新建Struct实例即可——构造开销很低本质上只是预解析 format 字符串并计算对齐后的size/len见 Modules/_struct.c 中set_format()的解析流程无需复用对象。二、标准库模块级版本属性__version__/version/VERSION全面移除弃用内容以下 24 个模块中的__version__、version和VERSION属性被弃用将在 3.20 移除统一改用sys.version_info由 Hugo van Kemenade 和 Stan Ulbrych 提交模块备注argparse__version__返回硬编码值csvctypesctypes.macholib仅 macOS 可用decimal改用decimal.SPEC_VERSIONhttp.serverimaplibipaddressjsonlogging__date__一并弃用optparsepickleplatformresocketservertabnannytarfiletkinter.fonttkinter.ttkwsgiref.simple_serverxml.etree.ElementTreexml.sax.expatreaderxml.sax.handlerzlib源码实现证据以 Lib/argparse.py 为例模块顶层使用 PEP 562 的模块级__getattr__实现惰性弃用L2972-L2976def __getattr__(name): if name __version__: warnings._deprecated(__version__, remove(3, 20)) return 1.1 # Do not change raise AttributeError(fmodule {__name__!r} has no attribute {name!r})注意warnings._deprecated(..., remove(3, 20))中的remove(3, 20)参数——它生成的警告文案会明确提示“将在 3.20 移除”。Lib/json/init.pyL390-L393采用完全相同的模式。这种实现还带来一个副作用值得注意一旦 3.20 移除该属性访问argparse.__version__将抛出AttributeError因此依赖getattr(module, __version__, unknown)兜底取值的代码会静默降级而直接属性访问的代码会直接崩溃。迁移方案import sys # 替代 json.__version__ / zlib.VERSION 等所有模块级版本读取 major, minor sys.version_info[:2] if sys.version_info (3, 12): ...两个例外需要特别处理decimal公告明确指出应改用decimal.SPEC_VERSION因为它记录的是 Decimal 模块实现的规格版本与解释器版本无对应关系import decimal print(decimal.SPEC_VERSION) # 如 (3, 0)logging.__date__一并弃用如需日志库日期信息请直接读取源码版本控制信息不要依赖运行时属性。三、PEP 829.pth文件的 import 行与编码要求弃用内容这是 PEP 829 在 3.20 落地时的两项具体弃用由 Barry Warsaw 提交.pth文件中的import行在{name}.pth文件里写 import 语句是旧有的“副作用钩子”此后每出现此类行都会产生弃用警告.pth文件编码默认解码方式从 locale 编码改为强制utf-8-sig即允许带 BOM 的 UTF-8。PEP 的措辞是“MUST be encoded in utf-8-sig”即包含非 ASCII 字符的.pth文件若仍按 locale 编码保存行为将不再可预期。背景与迁移site模块在启动时扫描site-packages中的.pth文件其中的目录行用于扩展sys.path而 import 行则会在解释器启动阶段执行任意代码——这正是它被弃用的原因启动期代码执行难以追踪且影响启动行为。迁移建议不要在.pth文件中写import xxx。确需在导入包时执行初始化逻辑应在包自身的__init__.py中完成确需注册钩子优先考虑在应用入口或sitecustomize.py中显式处理。若.pth文件包含中文注释等非 ASCII 内容请用 UTF-8带 BOM 更稳妥重新保存并在部署后确认site能正常解析避免在旧 locale 环境下行为不一致。四、ast禁止直接实例化抽象 AST 节点弃用内容公告指出创建抽象 AST 节点实例如ast.AST、ast.expr等中间抽象类已被弃用将在 3.20 直接抛出错误不再是警告。影响与迁移ast模块的类层次中ast.AST→ast.stmt/ast.expr/ast.keyword等抽象中间层用于分类而ast.Module、ast.FunctionDef、ast.Constant、ast.Name等具体节点才是可构造对象。3.20 之后import ast # 3.20 之前可实例化当前开发版已弃用3.20 起将抛错 node ast.expr() # 不要这样写 node ast.AST() # 不要这样写 # 正确做法只构造具体节点或通过解析/转换获得节点树 tree ast.parse(x 1) tree ast.Module(bodytree.body, type_ignores[]) # 具体节点合法依赖“构造抽象节点作为占位/基类探针”的第三方库或 AST 生成器需要在 3.20 前改为构造具体节点如用ast.Constant代替笼统的ast.expr占位。五、typing隐式 runtime-checkable 协议的 isinstance 检查弃用内容公告由 Bartosz Sławecki 提交对未显式用runtime_checkable装饰、但继承自某个 runtime-checkable 协议类的协议类执行isinstance/issubclass检查已被弃用3.20 起将抛出TypeError。语义解析在typing中runtime_checkable原本可以“隐式继承”——父协议被装饰后子协议也被动获得运行时检查资格。但隐式资格带来两个问题一是使用者无法从子类定义处看出它“碰巧可被 isinstance”二是结构兼容性的运行时检查本身只能核查公有成员存在性语义弱于显式声明。因此 3.20 的收紧方向是想要运行时协议检查就必须在类定义处显式装饰。from typing import Protocol, runtime_checkable runtime_checkable class Reader(Protocol): def read(self, n: int -1) - bytes: ... class BufferedReader(Reader): def read(self, n: int -1) - bytes: ... # 3.20 之前isinstance(b, Reader) 可用Reader 隐式继承了 runtime_checkable # 3.20 起将抛 TypeError除非显式装饰 runtime_checkable class BufferedReader(Reader): def read(self, n: int -1) - bytes: ...迁移策略对每个需要isinstance的协议显式添加runtime_checkable对只想做静态类型约束的协议保持不装饰并把运行期isinstance替换为显式的接口/类型标注。小结面向 3.20 的排查清单#弃用特性3.20 后果替代方案1Struct()无 format / 对已初始化 Struct 调__init__移除构造时一次性传入 format改格式就新建实例224 个标准库模块的__version__/version/VERSION移除访问抛AttributeErrorsys.version_infodecimal 用SPEC_VERSION3.pth文件 import 行、非 utf-8-sig 编码产生警告 / 解码行为改变移除 import 行.pth一律 utf-8-sig 保存4抽象 AST 节点ast.AST、ast.expr实例化抛出错误只构造具体节点或用ast.parse5隐式 runtime-checkable 协议上的isinstance/issubclass抛出TypeError显式runtime_checkable装饰排查手段建议在当前开发版开启-X dev默认显示弃用警告运行完整测试套件DeprecationWarning的文案中带有remove in 3.20字样可直接定位上述五类用法涉及 C 实现的第 1 项可对照 Modules/_struct.c 中s_new()L1883-L1950与Struct___init___impl()L1980-L2003的警告分支确认具体触发条件涉及 Python 标准库的第 2 项则可搜索各模块顶层的def __getattr__(name)与warnings._deprecated调用逐一核对。【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考