为 PyPy 编写扩展模块

本文档试图解释如何将 PyPy Python 解释器与任何外部库进行交互。

目前,为 PyPy Python 解释器提供第三方模块有以下几种可能性(按顺序,从最直接有用到最混乱的使用 PyPy):

  • 用纯 Python 编写它们并使用 CFFI.
  • 用纯 Python 编写它们并使用 ctypes.
  • 用 C++ 编写它们并通过 cppyy 使用 Cling 进行绑定。
  • 将它们编写为 RPython 混合模块.

CFFI

CFFI 是推荐的方式。它是一种编写纯 Python 代码以访问 C 库的方法。其理念是支持对 C 的 ABI 或 API 级访问 - 这样您就可以理智地访问 C 库,而无需依赖诸如 C 结构中的确切字段顺序或所有常量的数值之类的细节。它在 CPython(作为单独的 python -mpip install cffi)和 PyPy 上都有效,在 PyPy 上默认包含。

PyPy 的 JIT 对调用 C 函数或使用 CFFI 操作 C 指针的 Python 代码做了相当合理的处理。(截至 PyPy 2.2.1,它仍然可以改进,但已经很好了。)

请参阅 此处 的文档。

CTypes

PyPy 的 ctypes 模块的目标是尽可能与 CPython ctypes 版本兼容。它适用于大型示例,例如 pyglet。PyPy 的实现并非严格 100% 与 CPython 兼容,但对于大多数情况来说已经足够接近。更多(但较旧的)信息可在 此处 获得。此外,ctypes 的性能不如 CFFI 的好。

PyPy 使用围绕两个名为 _rawffi_rawffi.alt 的内置模块的纯 Python 代码实现 ctypes,这两个模块为 C 库 libffi 提供了非常底层的绑定。如今不建议直接使用这两个模块。

cppyy

对于 C++,_cppyy_ 是一种自动绑定生成器,可用于 PyPy 和 CPython。_cppyy_ 依赖于来自 C++ 头文件的声明来动态构建 Python 等效类、函数、变量等。它旨在供大型程序使用,并支持现代 C++。在 PyPy 中,它利用内置的 _cppyy 模块,允许 JIT 消除大多数跨语言开销。

要安装,请运行 <pypy> -mpip install cppyy。更多详细信息可在 完整文档 中找到。

RPython 混合模块

这是在 PyPy 中编写内置扩展模块的内部方式。任何第三方模块都无法使用它:扩展模块是内置的,而不是独立可加载的 DLL。

这保留用于特殊情况:它允许直接访问例如 JIT 的详细信息,使我们能够调整它与用户代码的交互。这就是 numpy 模块的开发方式。