除非另有文档说明,Python 的 C API 将遵循 PEP 387 所描述的向下兼容策略。 对它的大部分改变都是源代码级兼容的(通常只会增加新的 new API)。 改变现有 API 或移除 API 只会在弃用期结束之后或需修复严重问题时才会发生。 CPython 的应用程序二进制接口(ABI)可以跨微版本向上和向下兼容(在以相同方式编译的情况下,参见下文 平台的考虑 一节)。 因此,针对 Python 3.10.0 编译的代码将适用于 3.10.8,反之亦然,但对于 3.9.x 和 3.11.x 则需要单独编译。 存在具有不同稳定性预期的两个 C API 层次: 不稳定 API,可能在次要版本中发生改变而没有弃用期。 它的名称会以 PyUnstable 前缀来标记。
这些将在下文中更详细地讨论。 带有一个下划线前缀的名称,如 _Py_InternalState,是可能不经通知就改变甚至是在补丁发布版中改变的私有 API。 如果你需要使用这样的 API,请考虑联系 CPython 开发团队 来讨论为你的应用场景添加公有 API。 不稳定 C API任何名称带有 PyUnstable 前缀的 API 都将对外公开 CPython 的实现细节,并可能不加弃用警告即在次要版本中发生改变(例如从 3.9 到 3.10)。 但是,它不会在问题修正发布版中改变(例如从 3.10.0 到 3.10.1)。 它通常是针对专门的,低层级的工具如调试器等。 使用此 API 的项目需要跟随 CPython 开发进程并花费额外的努力来适应改变。 应用程序二进制接口的稳定版简单起见,本文档只讨论了 扩展,但受限 API 和稳定 ABI 对于 API 的所有用法都能发挥相同的作用 – 例如嵌入版的 Python 等。 受限 C APIPython 3.2 引入了 受限 API,它是 Python 的 C API 的一个子集。 只使用受限 API 扩展可以一次编译即适用于多个 Python 版本。 受限 API 的内容 如下所示。 [size=1.1em]Py_LIMITED_API
请在包括 Python.h 之前定义这个宏以选择只使用受限 API,并选择受限 API 的版本。 将 Py_LIMITED_API 定义为与你的扩展所支持的最低 Python 版本的 PY_VERSION_HEX 的值。 扩展将无需重编译即可适用于从该指定版本开始的所有 Python 3 发布版,并可使用到该版本为止所引入的受限 API。 不直接使用 PY_VERSION_HEX 宏,而是碍编码一个最小的次要版本(例如 0x030A0000 表示 Python 3.10)以便在使用未来的 Python 版本进行编译时保持稳定。 你还可以将 Py_LIMITED_API 定义为 3。 其效果与 0x03020000 相同(即 Python 3.2,引入受限 API 的版本)。 稳定 ABI为启用此特性,Python 提供了一个 稳定 ABI: 将能跨 Python 3.x 版本保持兼容的一组符号。 稳定 ABI 包含在 受限 API 中对外公开的符号,但还包含其他符号 – 例如,为支持旧版本受限 API 所需的函数。 在 Windows 上,使用稳定 ABI 的扩展应当被链接到 python3.dll 而不是版本专属的库如 python39.dll。 在某些平台上,Python 将查找并载入名称中带有 abi3 标签的共享库文件 (例如 mymodule.abi3.so)。 它不会检查这样的扩展是否兼容稳定 ABI。 使用方 (或其打包工具) 需要确保这一些,例如,基于 3.10+ 受限 API 编译的扩展不可被安装于更低版本的 Python 中。 稳定 ABI 中的所有函数都会作为 Python 的共享库中的函数存在,而不仅是作为宏。 这使得它们可以在不使用 C 预处理器的语言中使用。 受限 API 的作用域和性能受限 API 的目标是允许使用在完整 C API 中可用的任何东西,但可能会有性能上的损失。 在未定义 Py_LIMITED_API 的情况下,某些 C API 函数将由宏来执行内联或替换。 定义 Py_LIMITED_API 会禁用这样的内联,允许提升 Python 的数据结构稳定性,但有可能降低性能。 通过省略 Py_LIMITED_API 定义,可以使基于版本专属的 ABI 来编译受限 API 扩展成为可能。 这能提升其在相应 Python 版本上的性能,但也将限制其兼容性。 基于 Py_LIMITED_API 进行编译将产生一个可在版本专属扩展不可用的场合分发的扩展 – 例如,针对即将发布的 Python 版本的预发布包。 受限 API 警示请注意使用 Py_LIMITED_API 进行编译 无法 完全保证代码能够兼容 受限 API 或 稳定 ABI。 Py_LIMITED_API 仅仅涵盖定义部分,但一个 API 还包括其他因素,如预期的语义等。 Py_LIMITED_API 不能处理的一个问题是附带在较低 Python 版本中无效的参数调用某个函数。 例如,考虑一个接受 NULL 作为参数的函数。 在 Python 3.9 中,NULL 现在会选择一个默认行为,但在 Python 3.8 中,该参数将被直接使用,导致一个 NULL 引用被崩溃。 类似的参数也适用于结构体的字段。 另一个问题是当定义了 Py_LIMITED_API 时某些结构体字段目前不会被隐藏,即使它们是受限 API 的一部分。 出于这些原因,我们建议用要支持的 所有 Python 小版本号来测试一个扩展,并最好是用其中 最低 的版本来编译它。 我们还建议查看所使用 API 的全部文档以检查其是否显式指明为受限 API 的一部分。 即使定义了 Py_LIMITED_API,少数私有声明还是会出于技术原因(或者甚至是作为程序缺陷在无意中)被暴露出来。 还要注意受限 API 并不必然是稳定的:在 Python 3.8 上用 Py_LIMITED_API 编译扩展意味着该扩展能在 Python 3.12 上运行,但它将不一定能用 Python 3.12 编译。 特别地,在稳定 ABI 保持稳定的情况下,部分受限 API 可能会被弃用并被移除。
|