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 在转换前后是否具有相同的结果,如果测试失败,则添加一个 __reduce__ 方法,该方法引发 TypeError。请参阅 PR-21002 以获取示例。

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

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

流程

以下流程应添加到 Devguide 中,并在所有模块转换完成之前保持不变。任何新的发现都应记录在其中或通用 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

上次修改时间:2023-10-04 23:18:07 GMT