Python 稳定 ABI(应用程序二进制接口)提供了一种构建可跨不同 Python 版本保持兼容性的 C 扩展模块的方法。本文档介绍了什么是稳定 ABI,它是如何工作的,以及使用它来创建在 Python 更新后仍能保持稳定性的扩展模块的最佳实践。
有关创建 C 扩展模块的常规信息,请参阅扩展开发和 C API。
稳定 ABI 解决了 Python 扩展的二进制兼容性问题。如果没有它,为某一 Python 版本(例如 3.8)编译的 C 扩展必须为每个新版本(3.9、3.10 等)重新编译才能正常工作。稳定 ABI 保证:
稳定 ABI 在 Python 3.2(PEP 384)中引入,并在后续版本中得到扩展。
来源:Misc/stable_abi.toml1-63 Doc/c-api/stable.rst
要使用稳定 ABI 构建扩展模块,请执行以下操作:
Py_LIMITED_API 为您的扩展所需的最低 Python 版本(十六进制格式)。#include <Python.h>构建扩展时:
python3.dll(而不是特定版本的 python3X.dll)。宏 Py_LIMITED_API 应设置为目标最低 Python 版本(十六进制),格式为 0xMMmmNNpp,其中:
MM 是主版本号。mm 是次版本号。NN 是微版本号。pp 是补丁级别(通常为 0)。常见值包括:
0x03020000 表示 Python 3.2(首个支持稳定 ABI 的版本)。0x03060000 表示 Python 3.6。0x03070000 表示 Python 3.7。0x030A0000 表示 Python 3.10。来源:Include/Python.h30-46 Doc/c-api/stable.rst
下图说明了稳定 ABI 与完整 Python C API 和扩展之间的关系。
稳定 ABI 是完整 Python C API 的一个子集,仅包含保证在 Python 版本之间保持兼容性的函数、类型和其他符号。
来源:Misc/stable_abi.toml13-59 PC/python3dll.c1-14
这与需要为每个新 Python 版本重新编译的常规扩展形成对比。
来源:Include/Python.h47-52 Doc/whatsnew/3.13.rst616-617
稳定 ABI 由不同类型的项目组成:
| 组件类型 | 描述 | 示例 |
|---|---|---|
| 函数 | 保证保持其签名和行为的 C API 函数。 | PyDict_New()、PyList_Append()、PyLong_FromLong()。 |
| 结构体 | 具有不同暴露级别的 C 结构体定义。 | PyObject、PyTypeObject、PyModuleDef。 |
| 类型 | 用于函数签名的类型定义。 | PyObject*、Py_ssize_t、PyTypeObject*。 |
| 常量 | 用于 API 调用的命名值。 | Py_None、PyExc_ValueError。 |
| 宏 | 用于常见操作的预处理器定义。 | Py_INCREF()、Py_DECREF()。 |
稳定 ABI 中的结构体具有不同的暴露级别。
full-abi):整个结构体定义是稳定的,包括大小和字段布局。例如:PyMethodDef、PyModuleDef。opaque):只有指向结构体的指针是稳定的。内部布局可能会发生变化。例如:PyThreadState、PyInterpreterState。members):只有特定的成员属于 ABI。例如:PyObject(只有 ob_refcnt 和 ob_type 是稳定的)。来源:Misc/stable_abi.toml40-50 Include/object.h109-164
类型对象是稳定 ABI 的关键部分。
要使用稳定 ABI 创建类型对象,请使用 PyType_Spec 结构体和相关函数,而不是直接创建 PyTypeObject。
来源:Include/object.h374-385 Include/object.h386-415
稳定 ABI 随着时间的推移而增长,每个 Python 版本都添加了新的函数和功能。
| Python 版本 | 新增功能 | 重要新增内容 |
|---|---|---|
| Python 3.2 | 初始稳定 ABI (PEP 384) | 核心对象和类型系统,基本模块支持。 |
| Python 3.3 | 类型规范增强。 | PyType_FromSpecWithBases() |
| Python 3.4 | 槽内省。 | PyType_GetSlot() |
| Python 3.5 | 模块定义助手。 | PyModuleDef_Init() |
| Python 3.6 | 路径处理。 | PyOS_FSPath() |
| Python 3.7 | 内存和错误处理改进。 | PyMem_Calloc(),以及许多新的错误函数。 |
| Python 3.8 | 类型和集合改进。 | PyType_GetName()、PyIter_Check()。 |
| Python 3.9 | 类方法创建。 | PyCMethod_New() |
| Python 3.10 | 模块和迭代器实用工具。 | PyIter_Send()、PyModule_AddObjectRef()。 |
| Python 3.11 | 缓冲区协议和异常改进。 | Buffer API 函数。 |
| Python 3.12 | 异常显示改进。 | PyErr_DisplayException() |
| Python 3.13 | GIL 相关函数和优化。 | PyMem_RawCalloc() 及其系列函数。 |
完整的符号列表维护在 Misc/stable_abi.toml 中,并且可以在安装的 Doc/data/stable_abi.dat 文件中查看。
来源:Misc/stable_abi.toml147-620 Doc/data/stable_abi.dat1-500
稳定 ABI 与 Python 的多线程版本(无 GIL)不兼容。使用稳定 ABI 的扩展无法在全局解释器锁被禁用的 Python 版本中加载。
来源:Include/Python.h48-52 Doc/whatsnew/3.13.rst47-52
在使用稳定 ABI 时,内存管理变得尤为重要。请仅使用 Python 的内存管理函数,如 PyMem_Malloc(),而不是 C 标准库的 malloc()。这有助于避免内存损坏问题。
扩展应尽可能被隔离,并且不应依赖于每个进程的全局状态。尽可能使用每个模块的状态,如“隔离扩展”操作指南中所述。
这对于稳定 ABI 尤其重要,因为您的扩展可能会在存在多个解释器的环境中加载。
来源:Doc/howto/isolating-extensions.rst30-60
Python 测试套件包含验证所有稳定 ABI 符号是否可访问的测试。您也可以类似地测试您的扩展,以确保它仅使用稳定 ABI 符号,可以使用 ctypes 等工具。
来源:Lib/test/test_stable_abi_ctypes.py1-20
稳定的 ABI 提供了一种强大的方式来构建能够跨 Python 版本保持兼容性的扩展模块。通过将你的扩展限制为仅使用已定义的 Stable ABI 函数和类型,你可以创建二进制扩展,而无需为每个新的 Python 版本重新编译,从而使分发和维护更加容易。
在使用 Stable ABI 进行开发时,请记住:
Py_LIMITED_API 定义为你支持的最低 Python 版本这些实践将有助于确保你的扩展在不同 Python 版本上都能可靠运行。
刷新此 Wiki
最后索引时间2025 年 4 月 18 日(ea23c8)