将扩展模块移植到 Python 3
Benjamin Peterson
摘要
尽管更改 C-API 并不是 Python 3 的目标之一,但许多 Python 级别的更改使得 Python 2 的 API 无法完整实现。实际上,一些变化如 int() 和 的统一在 C 级别更明显。本文档致力于记录不兼容性以及如何解决这些问题。
仅编译 Python 3 的一些代码的最简单方法是检查 PY_MAJOR_VERSION
是否大于或等于3。
不存在的 API 函数可以在条件块中别名为它们的等价物。
Python 3 的 类型相当于 Python 2 的 unicode()
; C函数被称为 PyUnicode_*
。旧的 8 位字符串类型变为 bytes() ,其中 C 函数称为 PyBytes_*
。 Python 2.6 及更高版本提供了一个兼容性头文件 bytesobject.h
,将 PyBytes
名称映射到 PyString
。 为了保持与 Python 3 的最佳兼容性, PyUnicode
应该用于文本数据,并且 PyBytes
用于二进制数据。同样重要的是要记住 pyBytes
和 Python 3中的 不可互换,如 PyString
和 PyUnicode
在 Python 2 以下中示例显示了以下方面的最佳实践 PyUnicode
、 PyString
和 PyBytes
。:
long/int 统一
Python 3 只有一个整数类型, int() 。但它实际上对应于Python 2 long()
类型 —— 删除了 Python 2 中使用的 类型。在 C-API 中, PyInt_*
函数被它们等价的 PyLong_*
替换。
Python 3 有一个改进的扩展模块初始化系统。(参见 PEP 3121 。)而不是将模块状态存储在全局变量中,它们应该存储在特定于解释器的结构中。创建在 Python 2 和 Python 3 中正确运行的模块非常棘手。以下简单示例演示了如何操作。:
Capsule
对象是在 Python 3.1 和 2.7 中引入的,用于替换 CObject
。 CObject 是有用的,但是 API 是有问题的:它不允许区分有效的 CObject ,这导致不匹配的 CObject 使解释器崩溃,并且它的一些 API 依赖于 C 中的未定义行为。有关 Capsule 背后的基本原理的进一步阅读,请参阅 。)
如果你当前正在使用 CObject ,并且想要迁移到 3.1 或更高版本,则需要切换到 Capsules 。 CObject
在 3.1 和 2.7 中已弃用,在 Python 3.2 中已完全删除。如果你只支持 2.7 或 3.1 及以上,你可以简单地切换到 Capsule
。如果你需要支持 Python 3.0 或早于 2.7 的 Python 版本,则必须同时支持 CObject 和 Capsule 。(请注意,不再支持 Python 3.0 ,不建议将其用于生产用途。)
capsulethunk.h
使用 CObject 模拟 Capsules 。 但是, CObject
没有提供存储胶囊的“名称”的地方。因此,模拟 Capsule
对象由 capsulethunk.h
创建,其行为与真实 Capsule 略有不同。特别地:
如果你正在编写新的扩展模块,你可能会考虑 Cython 。 它将类似 Python 的语言转换为 C 。它创建的扩展模块与 Python 3 和 Python 2 兼容。