将扩展模块移植到 Python 3 — Python 文档
将扩展模块移植到 Python 3
- 作者
- 本杰明·彼得森
抽象的
尽管更改 C-API 不是 Python 3 的目标之一,但许多 Python 级别的更改使得保持 Python 2 的 API 完整是不可能的。 事实上,一些变化如 int() 和 long()
统一在 C 层面上更为明显。 本文档致力于记录不兼容性以及如何解决它们。
条件编译
只为 Python 3 编译一些代码的最简单方法是检查 PY_MAJOR_VERSION
是否大于或等于 3。
不存在的 API 函数可以在条件块中别名为它们的等效项。
对象 API 的变化
Python 3 将一些具有相似功能的类型合并在一起,同时干净地分离了其他类型。
str/unicode 统一
Python 3 的 str() 类型等价于 Python 2 的 unicode()
; 两者的 C 函数都称为 PyUnicode_*
。 旧的 8 位字符串类型变成了 bytes(),C 函数称为 PyBytes_*
。 Python 2.6 及更高版本提供了兼容性头文件 bytesobject.h
,将 PyBytes
名称映射到 PyString
名称。 为了与 Python 3 实现最佳兼容性,PyUnicode
应用于文本数据,PyBytes
用于二进制数据。 同样重要的是要记住 Python 3 中的 PyBytes
和 PyUnicode
不能像 Python 2 中的 PyString
和 PyUnicode
那样互换。 以下示例显示了关于 PyUnicode
、PyString
和 PyBytes
的最佳实践。
模块初始化和状态
Python 3 有一个改进的扩展模块初始化系统。 (参见 PEP 3121。)与其将模块状态存储在全局变量中,不如将它们存储在解释器特定的结构中。 创建在 Python 2 和 Python 3 中都能正确运行的模块是很棘手的。 以下简单示例演示了如何操作。
CObject 替换为 Capsule
Capsule
对象是在 Python 3.1 和 2.7 中引入的,用于替换 CObject
。 CObjects 很有用,但 CObject
API 有问题:它不允许区分有效的 CObjects,这允许不匹配的 CObjects 使解释器崩溃,并且它的一些 API 依赖于 C 中未定义的行为。 (有关 Capsule 背后原理的进一步阅读,请参阅 :issue:`5630`。)
如果您当前正在使用 CObjects,并且想要迁移到 3.1 或更高版本,则需要切换到 Capsules。 CObject
在 3.1 和 2.7 中被弃用,并在 Python 3.2 中完全删除。 如果你只支持2.7,或者3.1及以上,可以直接切换到【X68X】【X72X】。 如果需要支持 Python 3.0 或 Python 2.7 之前的版本,则必须同时支持 CObjects 和 Capsules。 (请注意,不再支持 Python 3.0,不建议将其用于生产用途。)
下面的示例头文件 capsulethunk.h
可以为您解决问题。 只需针对 Capsule
API 编写您的代码,并在 Python.h
之后包含此头文件。 您的代码将在带有 Capsules 的 Python 版本中自动使用 Capsules,并在 Capsules 不可用时切换到 CObjects。
capsulethunk.h
使用 CObjects 模拟 Capsule。 但是,CObject
没有提供存储胶囊“名称”的地方。 因此,由 capsulethunk.h
创建的模拟 Capsule
对象的行为与真实 Capsule 略有不同。 具体来说:
- 传入 PyCapsule_New() 的 name 参数被忽略。
- 传递给 PyCapsule_IsValid() 和 PyCapsule_GetPointer() 的名称参数被忽略,并且不执行名称错误检查。
- PyCapsule_GetName() 总是返回 NULL。
- PyCapsule_SetName() 总是引发异常并返回失败。 (由于无法在 CObject 中存储名称,因此 PyCapsule_SetName() 的嘈杂失败在这里被认为比静默失败更可取。 如果这样做不方便,请随意修改您认为合适的本地副本。)
您可以在 Python 源代码分发中找到 capsulethunk.h
作为 :source:`Doc/includes/capsulethunk.h`。 为方便起见,我们还将其包含在此处: