为 Python 写一个 C++ 扩展模块


为 Python 写一个 C++ 扩展模块

文章插图
导读:使用 C 扩展为 Python/ target=_blank class=infotextkey>Python 提供特定功能 。
本文字数:7993,阅读时长大约: 9分钟
 
使用 C 扩展为 Python 提供特定功能 。
 
在前一篇文章中,我介绍了 opensource.com 。在大多数系统上,CPython 是默认的解释器,而且根据民意调查显示,它还是最流行的解释器 。Cpython 的独有功能是使用扩展 API 用 C 语言编写 Python 模块 。用 C 语言编写 Python 模块允许你将计算密集型代码转移到 C,同时保留 Python 的易用性 。
在本文中,我将向你展示如何编写一个 C++ 扩展模块 。使用 C++ 而不是 C,因为大多数编译器通常都能理解这两种语言 。我必须提前说明缺点:以这种方式构建的 Python 模块不能移植到其他解释器中 。它们只与 CPython 解释器配合工作 。因此,如果你正在寻找一种可移植性更好的与 C 语言模块交互的方式,考虑下使用 docs.python.org 模块 。
源代码
和往常一样,你可以在 github.com 上找到相关的源代码 。仓库中的 C++ 文件有以下用途:
?my_py_module.cpp: Python 模块MyModule的定义
?my_cpp_class.h: 一个头文件 - 只有一个暴露给 Python 的 C++ 类
?my_class_py_type.h/cpp: Python 形式的 C++ 类
?pydbg.cpp: 用于调试的单独应用程序
本文构建的 Python 模块不会有任何实际用途,但它是一个很好的示例 。
构建模块
在查看源代码之前,你可以检查它是否能在你的系统上编译 。opensource.com 来创建构建的配置信息,因此你的系统上必须安装 CMake 。为了配置和构建这个模块,可以让 Python 去执行这个过程:
 
  1.  
    $ python3 setup.py build
     
 
或者手动执行:
 
  1.  
    $ cmake -B build
     
  2.  
    $ cmake --build build
     
 
之后,在/build子目录下你会有一个名为MyModule. so的文件 。
定义扩展模块
首先,看一下my_py_module.cpp文件,尤其是PyInit_MyModule函数:
 
  1.  
    PyMODINIT_FUNC
     
  2.  
    PyInit_MyModule(void) {
     
  3.  
    PyObject* module = PyModule_Create(&my_module);
     
  4.  
     
  5.  
    PyObject *myclass = PyType_FromSpec(&spec_myclass);
     
  6.  
    if (myclass == NULL){
     
  7.  
    return NULL;
     
  8.  
    }
     
  9.  
    Py_INCREF(myclass);
     
  10.  
     
  11.  
    if(PyModule_AddObject(module, "MyClass", myclass) < 0){
     
  12.  
    Py_DECREF(myclass);
     
  13.  
    Py_DECREF(module);
     
  14.  
    return NULL;
     
  15.  
    }
     
  16.  
    return module;
     
  17.  
    }
     
 
这是本例中最重要的代码,因为它是 CPython 的入口点 。一般来说,当一个 Python C 扩展被编译并作为共享对象二进制文件提供时,CPython 会在同名二进制文件中(.so)搜索PyInit_函数,并在试图导入时执行它 。
无论是声明还是实例,所有 Python 类型都是 docs.python.org 的一个指针 。在此函数的第一部分中,module通过PyModule_Create(...)创建的 。正如你在module详述(my_py_module,同名文件)中看到的,它没有任何特殊的功能 。
之后,调用 docs.python.org 为自定义类型


推荐阅读