PEP 408 – 标准库 __preview__ 包
- 作者:
- Alyssa Coghlan <ncoghlan at gmail.com>, Eli Bendersky <eliben at gmail.com>
- 状态:
- 已拒绝
- 类型:
- 标准跟踪
- 创建日期:
- 2012年1月7日
- Python 版本:
- 3.3
- 发布历史:
- 2012年1月27日
- 决议:
- Python-Dev 消息
摘要
将新模块包含到 Python 标准库的过程受到API锁定和模块正式成为Python一部分所隐含的向后兼容性承诺的阻碍。本PEP提出了模块的过渡状态——在完全被标准库接受之前,将模块包含在一个特殊的 __preview__ 包中,为期一个次要版本(大约18个月)。一方面,这种状态为模块提供了正式成为Python发行版一部分的好处。另一方面,核心开发团队明确表示,对于模块最终完全包含在标准库中,或其API的稳定性(可能会在下一个版本中更改)不作任何承诺。
PEP 驳回
根据他在 Google App Engine 中类似“labs”命名空间的经验,Guido 否决了此 PEP [3],转而采用更简单的替代方案,即在文档中明确将临时模块标记出来。
如果一个模块在其他方面被认为适合包含在标准库中,但仍存在一些关于可维护性或某些 API 细节的担忧,那么该模块可以被临时接受。虽然这被认为是不太可能的结果,但如果遗留的担忧被证实是合理的,这些模块可能会在没有弃用期的情况下从标准库中移除。
在同一份公告中,Guido 明确接受了 Matthew Barnett 的“regex”模块 [4] 作为 Python 3.3 标准库的临时添加(使用“regex”名称,而不是作为现有“re”模块的直接替换)。
提案 - __preview__ 包
每当 Python 核心开发团队决定将一个新模块包含到标准库中,但又不完全确定该模块的 API 是否最佳时,该模块可以在一个次要版本中放入一个名为 __preview__ 的特殊包中。
在下一个次要版本中,该模块可能会“毕业”到标准库(并占据其命名空间内的自然位置,离开 __preview__ 包),或者被拒绝并完全从 Python 源代码树中移除。如果该模块在 __preview__ 中度过一个次要版本后最终毕业到标准库,其 API 可能会根据累积的反馈进行更改。核心开发团队明确声明,对 __preview__ 中的模块的 API 稳定性和向后兼容性不作任何保证。
进入 __preview__ 包标志着模块向标准库过渡的开始。这意味着核心开发团队承担了该模块的责任,类似于标准库中的任何其他模块。
哪些模块应通过 __preview__
我们期望大多数提议添加到 Python 标准库中的模块都会在 __preview__ 中经历一个次要版本。但是,也可能有一些例外,例如使用预定义 API 的模块(例如 lzma,它通常遵循现有 bz2 模块的 API),或者其 API 在 Python 开发社区中已被广泛接受的模块。
无论如何,提议添加到标准库的模块,无论是通过 __preview__ 还是直接添加,都必须满足 PEP 2 设定的接受条件。
重要的是要强调,本提案的目的并非为了使将新模块添加到标准库的过程变得更加困难。相反,它试图提供一种方法来添加更多有用的库。显而易见的候选模块可以像以前一样添加。由于API不确定性而可能长期停滞的模块,现在可以通过在 __preview__ 包中的孵化期,获得与 Python 一起分发的途径。
“毕业”标准
原则上,__preview__ 包中的大多数模块最终应该会“毕业”到稳定的标准库。一些未能毕业的原因是:
- 该模块可能被证明不稳定或脆弱,缺乏足够的开发者支持来维护它。
- 在预览发布期间可能会找到一个更好的替代模块
本质上,核心开发人员将根据具体情况做出决定。此处需要强调的是,一个模块在某个版本中出现在 __preview__ 包中,并不能保证它在下一个版本中仍将是 Python 的一部分。
示例
假设 example 模块是纳入标准库的候选模块,但一些 Python 开发者并不确信它为要解决的问题提供了最佳 API。那么该模块可以在发布 3.X 时添加到 __preview__ 包中,通过以下方式导入:
from __preview__ import example
假设该模块在发布 3.X+1 时被提升到标准库中,它将被移动到库中的永久位置
import example
并且从 __preview__ 导入将不再有效。
基本原理
对核心开发团队的好处
目前,核心开发者们非常不愿向标准库添加新的接口。这是因为一旦它们在一个版本中发布,由于向后兼容性问题,API 设计错误就会被锁定。
通过让所有主要的 API 添加都经过某种预览机制,并在一个完整版本中进行,我们可以在将 API 锁定为我们的标准向后兼容性保证之前,获得一个完整发布周期的社区反馈。
我们也可以开始将预览模块与标准库的其余部分尽早集成,只要我们向打包者明确,预览模块不应被视为可选。预览 API 与标准库其余部分的唯一区别在于,预览 API 明确免除了通常的向后兼容性保证。
本质上,__preview__ 包旨在降低长期锁定次要 API 设计错误的风险。目前,这种担忧可能会阻碍新的添加,即使核心开发团队普遍认为某个添加原则上是一个好主意。
对最终用户的好处
对于未来的最终用户而言,最广泛的好处在于更好的“开箱即用”体验——而不是被告知“噢,用于任务 X 的标准库工具很糟糕,请下载这个第三方库”,那些更优秀的工具更有可能只需一个导入即可获得。
对于要求开发者对其上游依赖项进行尽职调查的环境(这严重损害了成本效益,甚至完全排除了 PyPI 上的大部分内容),关键好处在于确保 __preview__ 包中的任何内容都至少从以下角度明确处于 python-dev 的保护之下:
- 许可:由 PSF 根据贡献者许可协议重新分发。
- 文档:模块的文档通过标准 Python 文档工具发布和组织(即 ReST 源代码,使用 Sphinx 生成输出并发布在 https://docs.pythonlang.cn)。
- 测试:模块测试套件在 python.org buildbot 集群上运行,结果通过 https://pythonlang.cn/dev/buildbot 发布。
- 问题管理:错误和功能请求在 http://bugs.python.org 上处理。
- 源代码控制:软件的主仓库发布在 http://hg.python.org。
候选加入 __preview__ 的模块
对于 Python 3.3,有几个明确的当前候选者:
regex(http://pypi.python.org/pypi/regex)daemon(PEP 3143)ipaddr(PEP 3144)
其他可能的未来用例包括
与 PEP 407 的关系
PEP 407 建议修改 Python 核心发布周期,允许每 6 个月发布一次中期版本(可能仅限于标准库更新)。如果对发布周期进行此类更改,则建议对 __preview__ 命名空间采取以下策略:
- 对于长期支持版本,
__preview__命名空间将始终为空。 - 新模块只有在紧随长期支持版本之后的中期版本中才会被接受进入
__preview__命名空间。 - 所有添加的模块要么在下一个长期支持版本之前迁移到标准库的最终位置,要么完全移除。
被拒绝的替代方案和变体
使用 __future__
Python 已经有一个“前瞻性”命名空间,即 __future__ 模块,所以问为什么不能将其重新用于这个新目的也是合理的。
有两个原因说明这样做不合适:
1. __future__ 模块实际上与一个独立的编译器指令功能相关联,该功能可以改变 Python 解释器编译模块的方式。我们不希望预览包有这种情况——我们只是想要一个普通的 Python 包。
2. __future__ 模块附带了一个明确的承诺,即名称将永久保留,即使在相关功能成为编译器的默认行为之后很长时间。这与预览包的目的恰恰相反——几乎可以肯定的是,添加到预览中的所有名称都会在某个时候被删除,最可能是因为它们被移到了标准库中的永久位置,但也可能因为它们被恢复为第三方包状态(如果社区反馈表明提议的添加无法挽回地损坏)。
包的版本控制
一个提出的替代方案 [1] 是为 __preview__ 包添加明确的版本控制,即 __preview34__。我们认为,最好简单地定义一个模块在 Python 3.X 的 __preview__ 中,要么在 Python 3.X+1 中毕业到正常的标准库命名空间,要么完全从 Python 源代码树中消失。对 _preview__ 包进行版本控制会使过程复杂化,并且与本提案的主要意图不符。
使用不带前导和尾随下划线的包名
有人提议 [1] 使用像 preview 或 exp 这样的包名,而不是 __preview__。在讨论中,这个提议被拒绝了,因为“双下划线”包名(即带前导和尾随双下划线的名称)在 Python 中传达了特殊的含义。此外,非双下划线名称会暗示正常的标准库 API 稳定性保证,这与 __preview__ 包的意图不符。
保留 pickle 兼容性
在版本 3.X 中基于 __preview__ 包中的模块生成的 pickled 类实例,在版本 3.X+1 中将无法 unpickle,因为该模块将不在 __preview__ 中。可以添加特殊代码来实现此功能,但这与本提案的意图相悖,因为它意味着向后兼容性。因此,本 PEP 不提议保留 pickle 兼容性。
致谢
Dj Gilcrease 最初提出了在 Python 中拥有 __preview__ 包的想法 [2]。尽管他的原始提案使用了 __experimental__ 这个名称,我们认为 __preview__ 更好地传达了这个包的含义。
参考资料
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0408.rst