【问题标题】:Is Python C module extension version incompatible?Python C 模块扩展版本不兼容吗?
【发布时间】:2020-11-02 23:33:24
【问题描述】:
我在 Python 3.6 中编译了一个 python c 模块扩展。它在 Python 3.6 环境中运行良好,但在 Python 3.7 和 3.8 环境中无法运行,出现错误cannot import name 'cygrpc'。
我想知道这是预期的行为吗?如果是,是什么原因。
【问题讨论】:
-
我不相信这应该被关闭(因此我投票重新开放) - 答案足够明确,问题中的任何进一步细节都会分散注意力。我有点惊讶它不是重复的,但我找不到一个好的(this 是我能找到的最接近的)
标签:
python
cython
python-c-api
【解决方案1】:
这取决于扩展的编译方式以及它使用的 Python C API 接口。但是,是的,C 扩展通常必须针对特定版本的 Python 进行编译。在不知道如何创建扩展模块的情况下,我认为它需要重新编译。
通常,Python C API 会在每个版本中更改。如果该更改破坏了您的扩展程序中的某些内容,自然地,您必须为新的 API 接口更新您的扩展程序。但是,即使您的更改源代码兼容(无需更改源代码即可支持新的 Python 版本),这并不意味着编译后的二进制文件一定是兼容的。这就是 Binary 接口 (ABI) 发挥作用的地方。
另请参阅:Stable Application Binary Interface,其中描述了其背后的原因:
原因主要是结构定义的演变,其中添加新字段或更改字段类型可能不会破坏 API,但会破坏 ABI。因此,每个 Python 版本都需要重新编译扩展模块 [...]
还提到了二进制文件跨版本兼容的有限情况:
自 Python 3.2 起,已声明 API 的一个子集以保证稳定的 ABI。希望使用此 API(称为“受限 API”)的扩展模块需要定义 Py_LIMITED_API。一些解释器的细节会被扩展模块隐藏起来;作为回报,构建的模块可以在任何 3.x 版本 (x>=2) 上运行而无需重新编译。
因此,如果您只使用部分稳定 API 并定义 Py_LIMITED_API,则编译后的模块可能无需重新编译即可跨 Python 版本兼容。