PEP 421 – 添加 sys.implementation
- 作者:
- Eric Snow <ericsnowcurrently at gmail.com>
- BDFL 代表:
- Barry Warsaw
- 状态:
- 最终
- 类型:
- 标准跟踪
- 创建:
- 2012 年 4 月 26 日
- Python 版本:
- 3.3
- 历史记录:
- 2012 年 4 月 26 日
- 决议:
- Python-Dev 邮件
摘要
本 PEP 引入了一个新的 sys
模块属性:sys.implementation
。该属性包含有关正在运行的解释器实现的综合信息。因此,sys.implementation
是标准库查找特定于实现的信息的来源。
本 PEP 中的提案与更广泛地强调使 Python 对备选实现更加友好相一致。它描述了新的变量以及该变量包含的内容的约束。PEP 还解释了 sys.implementation
的一些直接用例。
动机
多年来,Python 语言和 CPython(参考实现)之间的区别一直在扩大。这种变化主要是因为 Jython、IronPython 和 PyPy 作为 Python 的可行备选实现而出现。
但是,请考虑近二十年来以 CPython 为中心的 Python(即它的大部分存在时间)。这种关注可以理解地导致了标准库中以及解释器中公开的相当多的特定于 CPython 的工件。尽管核心开发人员近年来努力解决这个问题,但相当多的工件仍然存在。
本 PEP 中提出了一部分解决方案:一个将实现细节整合到其中的单一命名空间。这将有助于集中精力将实现细节与语言区分开来。此外,它将培养多实现的心态。
提案
我们将向 sys
模块添加一个新属性,称为 sys.implementation
,作为一个具有属性访问的对象(而不是映射)。它将包含特定于实现的信息。
此对象的属性在解释器执行期间以及实现版本的整个过程中将保持不变。这确保了依赖于 sys.implementation
属性的行为不会在版本之间发生变化。
该对象具有下面 必需属性 部分中描述的每个属性。这些属性名称永远不会以下划线开头。标准库和语言定义将仅依赖于这些必需属性。
此提案采取了一种保守的方法,仅要求少量属性。随着更多属性变得合适,可以谨慎地添加它们,如 添加新的必需属性 中所述。
虽然此 PEP 对 sys.implementation
没有其他约束,但它也建议不要依赖于此处未描述的功能。该建议的唯一例外是以下划线开头的属性。实现者可以根据需要使用它们来存储特定于实现的数据。
必需属性
这些是 sys.implementation
中的属性,标准库和语言定义将依赖于这些属性,这意味着实现者必须定义它们
- name
- 表示实现的小写标识符。例如,“pypy”、“jython”、“ironpython”和“cpython”。
- version
- 实现的版本,而不是它实现的语言的版本。此值符合 版本格式 中描述的格式。
- hexversion
- 与
sys.hexversion
相同的十六进制格式的实现版本。 - cache_tag
- 用于 PEP 3147 缓存标签的字符串。它通常是名称和版本的组合(例如,CPython 3.3 的“cpython-33”)。但是,实现可以显式地使用不同的缓存标签。如果
cache_tag
设置为 None,则表示应禁用模块缓存。
添加新的必需属性
随着时间的推移,将向 sys.implementation
添加更多必需属性。但是,每个属性都必须在所有 Python 实现中都有有意义的用例才能被考虑。标准库或语言规范中的用例最能说明这一点。
所有关于新必需属性的提案都将通过正常的 PEP 流程。这样的 PEP 不需要很长,只要足够长即可。它需要充分说明新属性的基本原理、用例及其对各种 Python 实现的影响。
版本格式
sys.implementation
的一个主要目的是包含将在标准库内部使用的信息。为了促进版本属性的有用性,其值应在跨实现的统一格式中。
因此,sys.implementation.version
的格式将遵循 sys.version_info
的格式,后者实际上是一个命名元组。它是一种熟悉的格式,并且通常与正常的版本格式约定一致。
基本原理
特定于实现的信息现状使我们能够以更脆弱、更难以维护的方式获取该信息。它分散在不同的模块中或从其他信息中推断出来,正如我们在 platform.python_implementation() 中看到的那样。
本 PEP 是该方法的主要替代方案。它将特定于实现的信息整合到一个单一命名空间中,并使隐式信息明确化。
类型考虑
很容易陷入关于 sys.implementation
类型讨论的泥潭。但是,其目的是支持标准库和语言定义。因此,与其类型相比,关于其类型的任何内容都没有什么真正重要,这与更广泛使用的功能不同。因此,诸如不变性和序列性等特性已被忽略。
唯一的真正选择是在具有属性访问的对象和具有项访问的映射之间。本 PEP 主张使用点访问来反映命名空间的相对固定性质。
非必需属性
此 PEP 的早期版本包含一个名为 metadata
的必需属性,该属性包含任何非必需的特定于实现的数据 [16]。但是,考虑到 sys.implementation
的目的,这被证明是一个不必要的补充。
最终,本 PEP 几乎忽略了非必需属性。它们除了可能与未来的必需属性发生冲突之外没有其他影响。然而,对于 sys.implementation
来说,这只是一个次要问题。
为什么是 sys
的一部分?
sys
模块包含新的命名空间,因为 sys
是解释器中心变量和函数的存储库。许多特定于实现的属性已在 sys
中找到。
为什么对任何值都有严格的限制?
如 版本格式 中已经指出的那样,sys.implementation
中的值旨在供标准库使用。约束这些值,本质上是为它们指定一个 API,允许它们一致地使用,而不管它们是如何实现的。但是,应注意不要过度指定约束。
讨论
关于 sys.implementation
的主题在 2009 年的 python-ideas 列表中出现,当时反响普遍积极 [1]。我在最近开发纯 Python imp.get_tag()
时重新讨论了这个问题 [2]。讨论一直在进行 [3]。问题 #14673 中的消息也相关。
最近讨论的大部分内容都集中在用于 sys.implementation
的类型上。
用例
platform.python_implementation()
“显式优于隐式”
platform
模块通过查看几个不同的 sys
变量中的线索来确定 Python 实现 [11]。但是,这种方法很脆弱,每次实现更改时都需要更改标准库。除此之外,platform
中的支持仅限于核心开发人员在 platform
模块中通过特殊情况处理的那些实现。
使用 sys.implementation
,各种实现将显式地设置其自身版本的 sys
模块中的值。
另一个问题是 platform
模块是 stdlib 的一部分,理想情况下,它应该最大程度地减少诸如将移动到 sys.implementation
的实现细节。
如果 sys.implementation
和 platform
模块之间存在重叠,则只需使用 sys.implementation
(platform
中的相同接口对其进行包装)。
冻结的 importlib 中的缓存标签生成
PEP 3147 定义了模块缓存和用于文件名的缓存标签的使用。从 3.3 版本开始,冻结到 Python 二进制文件中的 importlib 引导代码在导入过程中使用缓存标签。引导 importlib 的项目的一部分是清理 Python/import.c 中不再需要的代码。
在 Python/import.c
中定义的缓存标签被硬编码为 "cpython" MAJOR MINOR
。对于 importlib,选项要么以相同的方式对其进行硬编码,要么以与 platform.python_implementation()
相同的方式猜测实现。
只要硬编码的标签仅限于 CPython 特定的代码,它就是可行的。但是,由于其他 Python 实现使用 importlib 代码来处理模块缓存,因此硬编码的标签将成为一个问题。
在这种情况下,直接使用 platform
模块是行不通的。importlib 引导程序中使用的任何模块都必须是内置的或冻结的,而 platform
模块既不属于前者也不属于后者。这正是最近人们对 sys.implementation
感兴趣的原因。
无论用于实现名称的结果如何,另一个问题与缓存标签中使用的版本有关。该版本很可能是实现版本而不是语言版本。但是,实现版本在标准库中并没有轻易地被识别出来。
特定于实现的测试
目前,测试套件中在 Lib/test
下存在许多特定于实现的测试。测试支持模块 (Lib/test/support.py) 提供了一些用于处理这些测试的功能。但是,与 platform
模块一样,test.support
必须进行一些 sys.implementation
可以避免的猜测。
Jython 的 os.name
技巧
在 Jython 中,os.name
设置为 'java' 以适应标准库中对 java 环境的特殊处理 [14] [15]。不幸的是,它掩盖了原本应该出现在那里的操作系统名称。 sys.implementation
将有助于避免这种特殊情况。目前,Jython 为正常的 os.name
值设置 os._name
。
使用 sys.(version|version_info|hexversion)
的问题
此 PEP 的早期版本错误地将 sys.version_info
(及其相关函数)称为 Python 语言的版本,而不是实现的版本。但是,情况并非如此。相反,它是 CPython 实现的版本。顺便说一句,sys.version_info
的前两个组件(主版本和次版本)也反映了语言定义的版本。
正如 Barry Warsaw 指出的那样,“sys.version_info
的语义在过去一直很模糊” [17]。通过 sys.implementation
,我们有机会通过首先为实现的版本建立一个明确的位置来改善这种情况。
此 PEP 没有做出其他努力来直接澄清 sys.version_info
的语义。无论如何,为实现提供一个明确的版本肯定有助于澄清与语言版本的区别。
来自其他 Python 实现者的反馈
IronPython
Jeff Hardy 回应了关于反馈的请求 [4]。他说,“我可能会在它被批准后的第二天添加它” [6]。他还对 sys.implementation
的类型和 metadata
属性(此后已从 PEP 中删除)提供了有用的反馈。
Jython
2009 年,Frank Wierzbicki 这样说(关于 Jython 实现所需的属性) [8]
Speaking for Jython, so far it looks like something we would adopt
soonish after it was accepted (it looks pretty useful to me).
PyPy
一些 PyPy 开发人员回应了关于反馈的请求 [9]。Armin Rigo 说 [10]
For myself, I can only say that it looks like a good idea, which we
will happily adhere to when we migrate to Python 3.3.
他还表示支持保持所需列表的精简。Armin 和 Laura Creighton 都表示,更好地编目 Python 的实现的努力将受到欢迎。这项工作(此 PEP 是一个小的开始)将单独考虑。
过去的努力
PEP 3139
PEP 3139(2008 年)建议清理 sys
模块,部分方法是将特定于实现的变量和函数提取到单独的模块中。PEP 421 是该想法的一个不太雄心勃勃的版本。虽然 PEP 3139 被拒绝了,但其目标在很大程度上反映在 PEP 421 中,尽管采用了更轻量级的方法。
PEP 399
更大的图景
值得再次注意的是,此 PEP 是更大范围的持续努力的一小部分,该努力旨在识别 Python 中特定于实现的部分并减轻其对替代实现的影响。
sys.implementation
是特定于实现的数据的焦点,充当语言、标准库和不同实现之间合作的纽带。随着时间的推移,sys.implementation
可能会在适当的情况下承担 sys
和其他内置/标准库模块的当前属性。这样,它就是一个 PEP 3137-lite,但从尽可能小的规模开始。
但是,如前所述,许多其他工作早于 sys.implementation
。它也不一定是这项工作的主要部分。相反,可以将其视为使 Python 对替代实现更加友好的工作基础设施的一部分。
备选方案
由于 sys 下的单命名空间方法相对简单,因此此 PEP 未考虑任何替代方案。
其他属性示例
这些仅仅是示例,不属于提案的一部分。其中大多数是在之前的讨论中提出的,但与本 PEP 的目标不符。(如果它们让你感到兴奋,请参阅 添加新的必需属性。)
- common_name
- 实现所知的区分大小写的名称。
- vcs_url
- 实现项目的 VCS 主存储库的 URL。
- vcs_revision_id
- 标识实现的 VCS 修订版本的值。
- build_toolchain
- 用于构建解释器的工具。
- build_date
- 解释器构建的时间戳。
- homepage
- 实现网站的 URL。
- site_prefix
- 实现的首选站点前缀。
- runtime
- 解释器正在运行的运行时环境,例如“公共语言运行时”(.NET CLR)或“Java 运行时可执行文件”。
- gc_type
- 使用的垃圾回收类型,如“引用计数”或“标记清除”。
未解决的问题
目前没有。
实现
此 PEP 的实现包含在 问题 #14673 中。
参考文献
版权
本文档已进入公有领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0421.rst
上次修改时间:2023-10-11 12:05:51 GMT