PEP 689 – 不稳定 C API 层级
- 作者:
- Petr Viktorin <encukou at gmail.com>
- 讨论至:
- Discourse 帖子
- 状态:
- 最终版
- 类型:
- 标准跟踪
- 要求:
- 523
- 创建日期:
- 2022 年 4 月 22 日
- Python 版本:
- 3.12
- 发布历史:
- 2022 年 4 月 27 日, 2022 年 8 月 25 日, 2022 年 10 月 27 日
- 决议:
- Discourse 消息
摘要
C-API 的一些函数和类型被指定为不稳定,这意味着它们在补丁(错误修复/安全)版本中不会改变,但可能会在次要版本之间(例如 3.11 和 3.12 之间)改变而无需弃用警告。
任何带有前导下划线的 C API 都被指定为内部,这意味着它可能在没有任何通知的情况下改变或消失。
动机与原理
不稳定 C API 层
Python C-API 目前分为三个稳定性层级
- 有限 API,具有高度兼容性预期
- 公共 API,遵循向后兼容性策略,在更改前需要弃用警告
- 内部(私有)API,可随时更改。
需要访问 CPython 内部工具(例如高级调试器和 JIT 编译器)的工具通常是为 CPython 的次要系列版本构建的,并假设所使用的 C-API 内部在补丁版本中不会改变。为了支持这些工具,我们需要在公共和私有 C-API 之间设置一个层级,保证在整个次要系列版本中的稳定性:即拟议的不稳定层级。
一些函数,例如 PyCode_New(),被文档化为不稳定(“直接调用[它]可能会使您绑定到精确的 Python 版本”),并且在实践中也经常发生变化。不稳定层级应该使其状态显而易见,即使对于那些不仔细阅读文档的人来说也是如此,从而使它们难以意外使用。
为私有 API 保留前导下划线
目前,CPython 开发者对 API 名称中前导下划线的确切含义存在分歧。它被用来表示两种不同的事物
- 在次要版本之间可能更改的 API,如这里提出的不稳定层级(例如,PEP 523 中引入的函数)。
- 私有 API,完全不应在 CPython 之外使用(例如,因为它可能在不通知的情况下更改,或者它依赖于非 CPython 代码无法保证的未文档化假设)。
不明确的含义使得下划线不如它应有的有用。如果它只标记私有 API,CPython 开发者可以更改带下划线的函数,或删除未使用的函数,而无需研究它们在 CPython 之外如何文档化或使用。
随着专用不稳定层级的引入,我们可以阐明前导下划线的含义。它应该只标记私有 API。
避免不必要地破坏代码
本 PEP 规定不稳定层级中的 API 应具有特殊的名称前缀。这意味着函数(宏等)将需要重命名。重命名后,旧名称应继续可用,直到发生不兼容的更改(即,直到调用站点无论如何都需要更新)。换句话说,仅仅更改函数的层级不应破坏用户的代码。
规范
C API 按稳定性预期分为三个“部分”(内部、公共和有限)。我们现在将它们称为稳定性层级,或简称层级。
将添加一个不稳定层级。
此层级中的 API(函数、类型等)将使用 PyUnstable_ 前缀命名,没有前导下划线。
它们将在用于公共 API 的头文件中声明(Include/*.h,而不是在 Include/unstable/ 这样的子目录中)。
将引入几条处理不稳定层级的规则
- 不稳定 API 在补丁版本之间不应有向后不兼容的更改,但可能在次要版本(3.x.0,包括 3.x.0 的 Alpha 和 Beta 版本)中更改或删除。此类更改必须记录并在“新增功能”文档中提及。
- 对这些 API 的向后不兼容更改应以使用它们的代码需要更新才能与新版本编译的方式进行(例如,应添加/删除参数,或重命名函数,但参数的语义含义不应改变)。
- 不稳定 API 应经过文档化和测试。
- 要将 API 从公共层级移动到不稳定层级,应在新名称
PyUnstable_*下公开它。旧名称应被弃用(例如使用
Py_DEPRECATED),但应继续可用,直到对 API 进行不兼容的更改。根据 Python 的向后兼容性策略(PEP 387),此弃用需要持续至少两个版本(没有 SC 例外)。但它也可以无限期持续 – 例如,如果 PEP 590 的“临时”_PyObject_Vectorcall今天添加,它最初将命名为PyUnstable_Object_Vectorcall,并且没有计划删除此名称。在以下情况下,允许进行不兼容的更改(从而删除已弃用的名称)而无需 SC 例外,如同该函数已经是不稳定层级的一部分
- 在 Python 3.12 之前引入的任何 API,其文档说明其稳定性低于默认值。
- 在 Python 3.12 之前引入的任何带有前导下划线的 API。
有关示例,请参阅本 PEP 中指定的初始不稳定 API。
- 要将内部 API 移动到不稳定层级,应在新名称
PyUnstable_*下公开它。如果旧名称已文档化或在外部广泛使用,则应继续可用,直到进行不兼容的更改(并且调用站点需要更新)。它应开始引发弃用警告(例如,使用
Py_DEPRECATED)。 - 要将 API 从不稳定层级移动到公共层级,应在没有
PyUnstable_*前缀的情况下公开它。旧名称应保持可用,直到 API 被弃用或删除。
- 即使在 Beta 功能冻结之后,也允许添加新的不稳定 API 用于现有功能,直到第一个发布候选版本。在 Beta 期间需要在核心开发讨论区或获得共识。
名为 PyUnstable_* 的 C API 的参考文档将自动显示带有指向不稳定层级文档链接的注释。
前导下划线
带有前导下划线的 C API,以及仅在 Py_BUILD_CORE 可用时才可用的 API,将被视为内部。这意味着
- 它可能在次要版本(3.x.0,包括 3.x.0 的 Alpha 和 Beta 版本)中未经通知而改变或删除。补丁版本或发布候选版本中的 API 更改应仅在绝对必要时进行。
- 它应仅在源代码注释或开发指南中记录,而不应在公共文档中记录。
- 在 Python 3.12 之前引入的已文档化或在外部广泛使用的 API 应如上所述移动到不稳定层级。
这可能在本 PEP 被接受后很久才发生。因此,在未来几年中,核心开发者在更改带下划线的 API 之前应进行一些研究,特别是如果它不需要
Py_BUILD_CORE。
鼓励 C API 用户在其代码库中搜索 _Py 和 _PY 标识符前缀,并将任何命中视为最终需要修复的问题 – 或者通过切换到现有替代方案,或者通过打开 CPython 问题来请求为其用例公开公共 API,并最终切换到该 API。
初始不稳定 API
以下 API 将在初始实现中移至不稳定层级,作为概念验证。
代码对象构造函数
PyUnstable_Code_New()(从PyCode_New重命名)PyUnstable_Code_NewWithPosOnlyArgs()(从PyCode_NewWithPosOnlyArgs重命名)
代码额外信息 (PEP 523)
PyUnstable_Eval_RequestCodeExtraIndex()(从_PyEval_RequestCodeExtraIndex重命名)PyUnstable_Code_GetExtra()(从_PyCode_GetExtra重命名)PyUnstable_Code_SetExtra()(从_PyCode_SetExtra重命名)
预计在 Python 3.12 中会有更多,无需另一个 PEP。
向后兼容性
C API 向后兼容性预期将更加明确。
所有重命名的 API 都将尽可能长时间地以旧名称提供。
如何教授此内容
这些更改影响高级 C 程序员,他们应该查阅更新的参考文档、开发指南和/或“新增功能”文档。
参考实现
https://github.com/python/cpython/compare/main…encukou:unstable-tier
被拒绝的想法
无特殊前缀
在本 PEP 的初始版本中,不稳定 API 没有 PyUnstable 前缀。相反,定义 Py_USING_UNSTABLE_API 会使 API 在给定的源文件中可用,表明承认该文件作为一个整体可能需要针对每个 Python 版本进行重新审视。
然而,后来决定不稳定性质需要通过单独的名称来公开。
下划线前缀
可以同时用前导下划线标记私有和不稳定 API。然而,这会稀释 _Py 前缀的含义。将前缀仅保留给内部 API,使其搜索变得轻而易举。
新的头文件目录
其他 API 层级有专门的头文件目录(Include/cpython/, Include/internal/)。
由于不稳定层级使用非常明显的命名约定,并且名称始终可用,因此像 Include/unstable/ 这样的目录是不必要的。
Python API
在 Python(而非 C)API 中添加类似的层级可能很好,例如对于 types.CodeType。然而,实现机制需要不同。这超出了本 PEP 的范围。
版权
本文档置于公共领域或 CC0-1.0-Universal 许可证下,以更宽松者为准。
来源:https://github.com/python/peps/blob/main/peps/pep-0689.rst
最后修改时间:2025-02-01 08:55:40 GMT