ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CPython 3.8.0a2 变更日志深度解析:从 `__debug__` 赋值防护到 `gc.get_objects` 代际参数,读懂一次 Alpha 版本的 Core 与 Library 演进

CPython 3.8.0a2 变更日志深度解析:从 `__debug__` 赋值防护到 `gc.get_objects` 代际参数,读懂一次 Alpha 版本的 Core 与 Library 演进 CPython 3.8.0a2 变更日志深度解析从__debug__赋值防护到gc.get_objects代际参数读懂一次 Alpha 版本的 Core 与 Library 演进【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython本文基于 CPython 仓库中的官方变更记录 Misc/NEWS.d/3.8.0a2.rst 展开。CPython 3.8.0a2 是 3.8 系列的第二个 Alpha 候选版本2019-02-25 发布变更记录覆盖 Core and Builtins、Library、Documentation、Tests、Windows、IDLE 六个分区共 40 余条更新。读完本文你将完整掌握这一版本引入的全部核心能力如gc.get_objects的可选代际参数、math.prod、statistics.NormalDist、cell 对象可构造化并能结合当前仓库源码逐条定位这些变更背后的实现文件与关键函数。一、如何阅读 CPython 的 NEWS.d 变更记录理解这份变更日志之前先理解 Misc/NEWS.d/ 目录的机制。CPython 采用碎片化 changelog模式每个被接受的 issuebpo 编号提交时都会向Misc/NEWS.d/写入一条独立的.rst片段每条片段固定包含四个元数据字段.. bpo: 36016 .. date: 2019-02-17-20-23-54 .. nonce: 5Hns-f .. section: Core and Builtinsbpo对应 CPython issue 追踪系统的编号date条目创建时间nonce随机值防止 git 合并时同一文件冲突section条目归属分区。发布某个候选版本时脚本会把该时间窗口内的片段按 section 归类汇总进对应版本文件——Misc/NEWS.d/3.8.0a2.rst 就是这样生成的成品。因此阅读这份文件等价于逐条审阅 3.8.0a2 相对 3.8.0a1 的全部已接受变更。本版本各分区条目分布为Core and Builtins 17 条、Library 16 条、Documentation 3 条、Tests 9 条、Windows 5 条、IDLE 3 条。以下按分区逐条解析并标注当前仓库中可核验的源码位置。二、Core and Builtins解释器核心与内建行为的 17 处变更2.1 对__debug__赋值抛出 SyntaxErrorbpo-36052变更原文Raise aSyntaxErrorwhen assigning a value to__debug__with the Assignment Operator.__debug__是__main__模块中的一个布尔标志-O/-OO优化选项通过它决定assert与if __debug__:语句是否保留。此前用户可以用__debug__ False这种赋值劫持它造成混淆且无实际意义。3.8.0a2 起这类赋值在编译期即被拒绝。在当前仓库源码中可以验证这一防护的落点Python/ast_preprocess.c 中AST 预处理阶段通过_PyUnicode_EqualToASCIIString(node_-v.Name.id, __debug__)检查目标名Python/bltinmodule.c 中__main__模块初始化时用PyDict_SetItemString(dict, __debug__, debug)注入该标志Python/initconfig.c 的-O帮助文本也印证其语义remove assert and__debug__-dependent statements; add .opt-1 before pyc。贡献者为 Stéphane Wirtel 与 Pablo GalindoPablo Galindo 在本版本中还贡献了gc.get_objects代际参数与math.prod两项。2.2 类变量写入提速约一倍bpo-36012变更原文Doubled the speed of class variable writes. When a non-dunder attribute was updated, there was an unnecessary call to update slots.这是一个 CPython 类型对象热路径上的性能修复当给类而非实例写入一个非 dunder 属性时旧代码会触发一次无谓的槽位slot更新调用。移除该冗余调用后类变量赋值性能翻倍。此类优化直接作用于type.__setattr__路径Objects/typeobject.c 中的type_setattro属于写ClassName.attr x这类元编程模式的性能收益。2.3__fspath__返回非法类型时的错误信息改进bpo-35942在允许传入os.PathLike对象的接口如open()、os.path系列函数中如果对象实现__fspath__但返回了既不是str也不是bytes的值3.8.0a2 起错误信息会明确说明错误来源即来自该对象的__fspath__而不再是一个含糊的TypeError。这直接服务于os.PathLike协议定义于Lib/os.py的调试体验。2.4gc.get_objects新增可选代际参数bpo-36016变更原文gc.get_objects can now receive an optional parameter indicating a generation to get objects from. Patch by Pablo Galindo.gc.get_objects()原本一次性返回所有被 GC 跟踪的对象新参数允许只取某一代generation的对象便于观察分代回收器中各代的内容分布。当前仓库的 C 实现位于 Modules/gcmodule.c/* [clinic input] gc.get_objects [when Python_PY_LIMITED_API] * generation: Py_ssize_t(accept{int, NoneType}, c_default-1) None Return a list of all objects that can be found by the garbage collector. If generation is not None, return only the objects tracked by the collector that are in that generation. [clinic start generated code]*/ static PyObject * gc_get_objects_impl(PyObject *module, Py_ssize_t generation) { PyThreadState *tstate _PyThreadState_GET(); if (generation NUM_GENERATIONS) { return PyErr_Format(PyExc_ValueError, generation parameter must be less than the number of available generations (%i), NUM_GENERATIONS); } if (generation -1) { return PyErr_Format(PyExc_ValueError, generation parameter cannot be negative); } PySys_Audit(gc.get_objects, n, generation); return _PyGC_GetObjects(interp, (int)generation); }从源码结构看参数默认值-1表示不限制代际传-1或省略参数即保持旧的全量返回行为非法值 NUM_GENERATIONS或 -1抛出ValueError。同时注意该实现带有PySys_Audit审计钩子安全审计工具sys.addaudithook可以拦截调用。配套使用的还有gc.get_stats()按代返回统计字典见 Modules/gcmodule.c 的帮助文本与三档阈值/计数的管理接口。2.5 未捕获 KeyboardInterrupt 时进程按 SIGINT 语义退出bpo-1054041变更原文When the main interpreter exits due to an uncaught KeyboardInterrupt, the process now exits in the appropriate manner for its parent process to detect that a SIGINT or ^C terminated the process.这是一个影响运维与脚本行为的修复此前 Python 进程因 Ctrl-C 退出时父进程shell、批处理脚本、进程管理器无法用WIFSIGNALED之类的方式区分被信号终止与正常退出。3.8.0a2 起进程以信号终止的语义退出shell 能正确识别用户主动中断退出状态 130 的惯例行为由此可靠。2.6 自定义不可下标元类下__class_getitem__修复bpo-35992修复当类带有自定义的、不支持__getitem__的元类时__class_getitem__没有被调用的问题。__class_getitem__是 3.7 引入的类下标协议用于typing.Generic别名式写法如MyClass[int]此修复保证即使元类自身不可下标协议方法也能正常参与调用。2.7 子解释器 fork 崩溃修复bpo-35993与_randommodule.c双重释放修复bpo-35991bpo-35993修复使用 subinterpreters子解释器_interpreters扩展时fork()导致的崩溃由 Stéphane Wirtel 贡献——这是 3.8 子解释器方向的重要稳定性工作bpo-35991修复 Modules/_randommodule.c 中一处潜在的 double free。random模块 C 实现中的双重释放属于内存安全隐患通常在多线程/边界时序下触发。2.8slice_richcompare崩溃修复bpo-35961变更原文Fix a crash in slice_richcompare(): use strong references rather than stolen references for the two temporary internal tuples.这是引用计数纪律问题切片对象slice参与比较运算时内部会构造两个临时元组旧代码使用了窃取引用stolen reference而非强引用导致对象在比较过程中可能被提前释放而崩溃。Objects/sliceobject.c 中slice_richcompare的临时对象生命周期管理随之修正。2.9 cell 对象可构造types.CellType公开bpo-35911变更原文Enable the creation of cell objects by adding acell.__new__method, and expose the typecellinLib/types.pyunder the name CellType. Patch by Pierre Glaser.cell 对象是闭包背后的载体function.__closure__里存的元素此前不可直接构造只能通过闭包间接获得。此变更做了两件事为 C 层cell类型补充__new__实现位于 Objects/cellobject.c并在Lib/types.py中公开CellType。当前仓库 Lib/types.py 中的回退实现展示了标准取值技巧——通过一个闭包拿到自己的 celldef _cell_factory(): a 1 def f(): nonlocal a return f.__closure__[0] CellType type(_cell_factory())该片段仅在import _types失败时作为纯 Python 回退执行正常构建下CellType由 C 模块_types提供Lib/types.py顶部第 11 行即from _types import *。有了CellType开发者可以在不借助闭包的情况下直接创建 cell 容器并读写其中的值对解释器扩展与元编程工具是实用的底层能力。2.10 条件变量等待使用单调时钟bpo-12822变更原文Use monotonic clock for pthread_cond_timedwait when pthread_condattr_setclock and CLOCK_MONOTONIC are available.threading的条件变量带超时等待底层调用pthread_cond_timedwait。此前使用CLOCK_REALTIME的话系统墙钟被 NTP 校时或手动修改会使超时判断失真。3.8.0a2 起在平台同时提供pthread_condattr_setclock与CLOCK_MONOTONIC时改用单调时钟超时语义不再受系统时间跳变影响。相关实现在 Modules/_threadmodule.c。2.11 编译器对元组/列表前疑似漏逗号发出语法警告bpo-15248变更原文The compiler emits now syntax warnings in the case when a comma is likely missed before tuple or list.经典笔误场景x (1, 2) (3, 4) # 漏写逗号实际是调用结果几乎总是 TypeError3.8.0a2 起编译器对这类字面量后紧跟元组/列表字面量的形态发出 SyntaxWarning把运行期才暴露的 bug 提前到编译期。该警告有配套测试工具函数见下文 Tests 部分 bpo-35798 的test.support.check_syntax_warning。2.12PyInterpreterState移入内部头文件bpo-35886变更原文The implementation of PyInterpreterState has been moved into the internal header files (guarded by Py_BUILD_CORE).这是子解释器计划PEP 507 方向的关键重构PyInterpreterState的结构体定义从公共 API 头 Include/pystate.h 移入Include/internal/下的内部头文件并以Py_BUILD_CORE宏保护。从源码结构看这标志着PyInterpreterState正式从稳定 C API 降级为内部实现细节为后续在结构上安全增删字段子解释器需要大量新字段铺路。对外部 C 扩展而言直接触碰PyInterpreterState字段的代码自 3.8 起不再受支持。2.13object.__new__/object.__init__参数错误信息澄清bpo-31506当object.__new__或object.__init__收到超过一个参数时例如某处误写object.__init__(self, extra)3.8.0a2 起报告的错误信息更明确地指出了是哪个方法、为何拒绝多参数便于定位元类/__new__参数传递错误这类疑难 bug。实现位于 Objects/typeobject.c 中object.__new__/object.__init__的分发逻辑。2.14 信号处理保证相对主解释器进行bpo-35724变更原文Signal-handling is now guaranteed to happen relative to the main interpreter.信号是进程级资源而 Python 信号回调是解释器级的多解释器环境下二者错位曾导致未定义行为。此条确立了保证信号处理逻辑固定锚定在主解释器上。2.15 新增内部接口_Py_AddPendingCall()bpo-33608变更原文We added a new internal _Py_AddPendingCall() that operates relative to the provided interpreter. This allows us to use the existing implementation to ask another interpreter to do work that cannot be done in the current interpreter, like decref an object the other interpreter owns. The existing Py_AddPendingCall() only operates relative to the main interpreter.pending call 机制是解释器间协作的管道把稍后在某个解释器的字节码循环里执行的回调排入队列。公开的Py_AddPendingCall()只能针对主解释器新的内部函数_Py_AddPendingCall()可指定任意目标解释器典型用途是请另一个解释器替我 decref 它拥有的对象——对象属于哪个解释器就必须在哪里释放这是子解释器正确性的基础。该接口现可在 Include/internal/pycore_ceval.h 及 Python/ceval.c 的 pending-call 处理路径中找到。2.16list.sort对无比较类型对象的崩溃修复bpo-33989变更原文Fix a possible crash inlist.sortwhen sorting objects withob_type-tp_richcompare NULL.某些 C 扩展类型不实现tp_richcompare比较钩子为空对其调用list.sort()曾触发空指针解引用。修复后 Objects/listobject.c 所描述的排序比较路径能正确将不支持比较转化为 Python 层TypeError而非崩溃补丁由 Zackery Spytz 提供。三、Library标准库的 16 处变更3.1 新增math.prodbpo-35606变更原文Implementmath.prodas analogous function tosumthat returns the product of a start value (default: 1) times an iterable of numbers. Patch by Pablo Galindo.math.prod(iterable, start1)是sum的乘法对偶求可迭代对象的连乘start默认 1。语义要点 math.prod([1, 2, 3, 4]) 24 math.prod([1, 2, 3, 4], start10) 240 math.prod([]) # 空可迭代对象返回 start 1当前仓库中其 C 实现为 Modules/mathmodule.c 的math_prod_impl签名(PyObject *module, PyObject *iterable, PyObject *start)与math.fsum等纯 C 数学函数同族Lib/test/test_math.py提供对应行为测试。3.2 新增statistics.NormalDist与statistics.fmeanbpo-36018 / bpo-35904statistics.NormalDist正态分布随机变量的创建与操作工具把均值与标准差作为单一实体处理的复合类支持cdf、pdf、inv_cdf、sample、分布算术相加、缩放等能力是 3.8 标准库统计模块的重要增强statistics.fmeanmean的更快纯浮点变体——直接对数据求算术平均并返回float不做分数Fraction精度的保守处理适合大数据量场景。当前仓库 Lib/statistics.py 中可见其实现def fmean(data, weightsNone)当前版本还扩展了weights加权参数是后续迭代的产物。3.3shutil.which支持 bytesbpo-18283shutil.which()此前只接受str路径3.8.0a2 起可接受bytes在PATH为bytes的进程内查找可执行文件。3.4unittest.mock.patch.dict装饰器惰性解析目标bpo-35512变更原文unittest.mock.patch.dictused as a decorator with string target resolves the target during function call instead of during decorator construction.用字符串目标如patch.dict(os.environ)装饰函数时模块查找时机从装饰器构造期改为被装饰函数调用期。这与patch其他用法的行为对齐修复了装饰器在模块导入早期执行、目标尚不可用时的失败问题。3.5dataclasses.field空 mapping metadata 修复bpo-35960dataclass中field(metadata{})传入空 mapping 时曾被丢弃修复后空metadata也得到保留行为与非空 mapping 一致。3.6Mock.assert_called_with断言错误分两行输出bpo-35500unittest.mock断言失败时期望参数expected与实际参数actual不再挤在同一行而是各占一行方便长参数列表的目视比对。由 Susan Su 贡献。3.7pdb的debug命令优雅处理语法错误bpo-35931调试器中执行debug命令临时表达式调试遇到语法错误时不再抛未处理异常而是友好报错。3.8http.server绑定地址改用 getaddrinfobpo-24209变更原文In http.server script, rely on getaddrinfo to bind to preferred address based on the bind parameter. Now default bind or binding to a name may bind to IPv6 or dual-stack, depending on the environment.python -m http.server的bind参数解析从手工地址解析改为依赖socket.getaddrinfo默认绑定或按主机名绑定时可能落到 IPv6 或双栈取决于系统环境。3.9_frozen_importlib的__spec__.origin置为 frozenbpo-35321由 Nina Zakharenko 补丁把_frozen_importlib的__spec__.origin设为frozen使其与_frozen_importlib_external的行为一致。这是 importlib 冻结模块元数据正确性的小修正。3.10multiprocessing.Pool生命周期引用修复bpo-35378变更原文较长核心是Pool在未显式close()/terminate()的情况下被删除后仍可能存活资源引用问题。修复方式是给 pool 的迭代器增加对 pool 本身的强引用把 pool 生命周期与其迭代器绑定——只要迭代器还活着pool 就不会被销毁。相关实现见 Lib/multiprocessing/pool.py。3.11re模块跨次匹配的捕获组残留修复bpo-34294变更原文re.search,re.findall,re.suband other functions that scan through string looking for a match, should reset capturing groups between two match attempts.扫描型函数在两次匹配尝试之间应重置捕获组。此前的缺陷会导致第 N 次匹配未命中的捕获组残留上一次匹配的值产生错误的分组结果——由 Ma Lin 修复属于边界场景的正确性修复。3.12weakref弱引用字典拷贝时 RuntimeError 修复bpo-35615拷贝WeakKeyDictionary/WeakValueDictionary时若迭代期间某些键/值被回收曾抛RuntimeError: dictionary changed size during iteration修复后拷贝过程安全跳过消失条目。实现见 Lib/weakref.py。3.13datetime子类算术保留子类型bpo-32417变更原文Performing arithmetic betweendatetime.datetimesubclasses anddatetime.timedeltanow returns an object of the same type as thedatetime.datetimesubclass. As a result,datetime.astimezoneand alternate constructors likedatetime.nowanddatetime.fromtimestampcalled with atzargument now also retain their subclass.自定义datetime子类与timedelta做加减时结果类型回到基类datetime而非子类破坏了子类的状态不变式。修复后运算结果保留子类类型副作用也是收益是astimezone(tz)、now(tz)、fromtimestamp(ts, tz)这些内部做减法时区替换的构造路径也自动保留子类。3.14xmlrpc.client三处新增headers关键字参数bpo-35153xmlrpc.client.ServerProxy、xmlrpc.client.Transport、xmlrpc.client.SafeTransport新增可选的仅关键字参数headers便于统一注入自定义 HTTP 头如认证头由 Cédric Krier 补丁提供。3.15 C 版pickle.loads改用 importlib 锁机制bpo-34572C 实现反序列化时导入新模块的时机曾可能拿到半初始化的模块。修复后pickle.loadsC 路径在导入新模块时走importlib的加锁机制避免使用部分加载的模块由 Tim Burgess 补丁提供。3.16 移除SyncManager.dict的坏方法has_keybpo-35918multiprocessing.managers.SyncManager暴露的字典代理上一直挂着早已废弃Python 2 时代的has_key方法且实现已损坏。3.8.0a2 将其移除用户应使用key in d语法。四、Documentation / Tests / Windows / IDLE外围四组变更4.1 Documentation3 条bpo-36083修复 man page源码为 Misc/python.manSynopsis 中--check-hash-based-pycs选项的排版bpo-36007文档构建所用 Sphinx 最低版本提升至 1.8对应 Doc/requirements.txt / Doc/conf.py 的约束由 Anthony Sottile 补丁bpo-22062pathlib文档与 docstring 全面更新原始补丁由 Mike Short 提供。4.2 Tests9 条bpo-27313规避 macOS Cocoa Tk 环境下test_ttk_guionly的ComboboxTest失败bpo-36019新增test.support.TEST_HTTP_URL常量替换测试中散落的http://www.example.com字面量Stéphane Wirtel 贡献bpo-36037修复严格 OpenSSL 策略如 RHEL8 严格加密策略下的test_ssl在必要时调低服务端 SSL 上下文的最小 TLS 版本以覆盖旧 TLS 版本用例bpo-35798新增test.support.check_syntax_warning——正是配合 2.11 节漏逗号语法警告这类编译期警告的测试断言工具bpo-35505test_imap4_host_default_value不再依赖本地 IMAP 服务器是否运行bpo-35917为SyncManager、SharedMemoryManager及其全部可共享类型补充单元测试Giampaolo Rodola 补丁bpo-3570432 位 AIX 且 MAXDATA 0x20000000 时跳过test_shutil.test_unpack_archive_xztar以防 MemoryErrorMichael Felt / aixtools 补丁bpo-34720GC 遍历测试中断言m_state ! NULL模拟那些未正确处理模块状态未创建情形的 GC 遍历函数以上共同特点是让 CPython 自身测试套件在更多平台macOS、RHEL8、AIX、严格 TLS 环境上稳定可跑。4.3 Windows5 条bpo-35976PCbuild目录见 PCbuild/pcbuild.sln 等工程文件新增 ARM 构建支持bpo-35692对未就绪驱动器如空的软驱/光驱盘符做文件/目录存在性检查时pathlib不再抛异常bpo-35872在虚拟环境内调用venv创建新环境时改用底层基础 Python 可执行文件而非当前 venv 的解释器bpo-35873防止 venv 相关路径VIRTUAL_ENV等被子进程继承避免环境嵌套污染bpo-35299修复 PGO profiling 期间sysconfig对源码目录的探测以及distutils对pyconfig.h的处理。4.4 IDLE3 条bpo-24310补充文档中 IDLE 设置对话框Font选项卡样例说明bpo-35833修订发送到 Shell 的控制码一节文档并补充代码示例块bpo-35689为Lib/idlelib/colorizer.py见 Lib/idlelib/colorizer.py补充 docstring 与单元测试。五、结语如何把这份变更日志用于工程实践3.8.0a2 变更记录 展示了 CPython Alpha 阶段的典型工作重心子解释器PEP 507 方向的系统性铺垫——PyInterpreterState内移bpo-35886、_Py_AddPendingCallbpo-33608、信号处理锚定主解释器bpo-35724、fork 崩溃修复bpo-35993、pending-call 跨解释器协作五处变更互相咬合为同一进程多解释器打地基API 的正确性补全——gc.get_objects代际参数、math.prod、statistics.NormalDist、CellType均为后续版本长期使用的公开 API 的起点可在 Doc/whatsnew/3.8.rst 中看到它们的成文版本稳定性与平台兼容性长尾——slice_richcompare强引用、list.sort空比较钩子、_randommoduledouble free、Windows venv 路径隔离等都是小修复、大面的质量工作。对使用者而言判断该不该升级时按 section 定位Library 影响面最广、Core and Builtins 影响运行语义再逐条读 bpo 条目是最高效的 changelog 阅读姿势对贡献者而言Misc/NEWS.d/的片段化机制bpo date nonce section 四字段正是值得借鉴的 changelog 工程化方案。【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表