将扩展模块移植到 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中的 不可互换,如 PyStringPyUnicode 在 Python 2 以下中示例显示了以下方面的最佳实践 PyUnicodePyStringPyBytes 。:

    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 兼容。