Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 687 – 标准库中模块的隔离

作者:
Erlend Egeberg Aasland <erlend at python.org>, Petr Viktorin <encukou at gmail.com>
讨论至:
Discourse 帖子
状态:
已接受
类型:
标准跟踪
要求:
489, 573, 630
创建日期:
2022年4月4日
Python 版本:
3.12
发布历史:
2022年4月4日, 2022年4月11日
决议:
Discourse 消息

目录

摘要

标准库中的扩展将转换为多阶段初始化(PEP 489),并且在可能的情况下,所有状态都将存储在模块对象上,而不是存储在进程全局变量中。

关于回溯的说明

本提案的大部分内容已经实现。我们提交此PEP以解释这些更改,寻求对它们是否有利的共识,提出剩余的更改,并为新模块设定最佳实践。

动机与原理

信息性的PEP 630描述了拟议更改的背景、动机、原理、影响和实现说明,因为它们通常适用于任何扩展模块(不仅仅是标准库)。

它是本提案的组成部分。请先阅读它。

此PEP讨论了标准库的具体细节。

规范

PEP 630 的正文将转换为Python文档中的HOWTO,并且该PEP将被废弃(标记为最终)。

标准库中的所有扩展模块都将转换为PEP 489中引入的多阶段初始化。

所有标准库扩展模块都将是*隔离的*。也就是说

  • 模块定义的类型、函数和其他对象要么是不可变的,要么不与其他模块实例共享。
  • 模块特有的状态不会与其他模块实例共享,除非它表示全局状态。

    例如,_csv.field_size_limit 将获取/设置模块特定的数字。另一方面,像 readline.get_history_itemos.getpid 这样的函数将继续处理进程全局(模块外部,并可能在其他库(包括非Python库)之间共享)的状态。

转换为堆类型

不需要模块状态访问且没有其他理由转换的静态类型应保持静态。

其方法需要访问其模块实例的类型将根据PEP 630转换为堆类型,并考虑以下事项

  • 所有以前是静态类型的标准库类型都应保持不可变。堆类型必须使用Py_TPFLAGS_IMMUTABLE_TYPE标志定义以保持不可变性。请参阅bpo-43908

    测试应确保在尝试创建不可变类型的新属性时引发TypeError

  • tp_new = NULL的静态类型没有公共构造函数,但堆类型从基类继承构造函数。确保以前无法实例化的类型保留该特性;使用Py_TPFLAGS_DISALLOW_INSTANTIATION。添加使用test.support.check_disallow_instantiation()的测试。请参阅bpo-43916
  • 转换后的堆类型可能会无意中变为可序列化(可pickle)。测试调用pickle.dumps在转换前后是否具有相同的结果,如果测试失败,则添加一个引发TypeError__reduce__方法。有关示例,请参阅PR-21002

这些问题将添加到开发指南中,以帮助未来的任何转换。

如果发现其他类型的问题,相关模块应保持不变,直到找到解决方案并添加到开发指南中,并且已转换的模块经过检查和修复。

流程

以下过程应添加到开发指南中,并保持不变,直到所有模块都已转换。任何新发现都应记录在那里或通用HOWTO中。

第1部分:准备

  1. 在错误跟踪器或Discourse上发起讨论。让模块维护者和/或代码所有者参与。解释更改的原因和原理。
  2. 识别全局状态性能瓶颈。创建概念验证实现,并测量性能影响。pyperf是一个很好的基准测试工具。
  3. 创建实施计划。对于类型较少的小模块,一个PR可能就足够了。对于类型较多,并且可能还有外部库回调的较大模块,将需要多个PR。

第2部分:实现

注意:这是基于从其他模块吸取的经验教训,针对复杂模块的建议实现计划。对于较小的模块,请随意简化。

  1. 尽可能添加Argument Clinic;它使您能够轻松地使用定义类从类型方法中获取模块状态。
  2. 准备模块状态;建立一个模块状态struct,添加一个实例作为静态全局变量,并创建用于获取模块状态的辅助存根。
  3. 将相关的全局变量添加到模块状态struct,并修改访问全局状态的代码以使用模块状态辅助函数。此步骤可以分解为多个PR。
  4. 在必要时,将静态类型转换为堆类型。
  5. 将全局模块状态结构转换为真正的模块状态。
  6. 实现多阶段初始化。

步骤4到6最好在一个alpha开发阶段完成。

向后兼容性

标准库中的扩展模块现在可以多次加载。例如,从sys.modules中删除此类模块并重新导入它将导致一个新的模块实例,与任何先前加载的实例隔离。

这可能会影响预期先前行为的代码:扩展模块的全局变量是从第一个加载的模块中浅层复制的。

安全隐患

未知。

如何教授此内容

本提案的很大一部分是面向经验用户的HOWTO,它将被移至文档中。

初学者不应受到影响。

参考实现

大部分更改现在都在主分支中,作为这些问题的提交

例如,在_csv模块中完成的更改和修复是


来源:https://github.com/python/peps/blob/main/peps/pep-0687.rst

最后修改:2025-02-01 08:55:40 GMT