Python调用C函数的方法以及如何编写Python的C扩展

前言

前言属闲聊,正文请转后。

标题比较长,其实“如何用Python调用C的函数”以及“如何编写Python的C扩展”在广义上是同一件事,因为都是用C写底层实现,用Python作接口。

具体方法有很多,比如用ctypes、用SWIG等等,各种方法有利有弊。前段时间笔者用SWIG编译某小段函数一直出BUG,检查了两天才发现原来是因为MinGW 32-bitPython 64-bit不兼容,加之后续笔者还需要用到NumPy C-API,所以现在笔者已弃坑SWIG,转用以下方法:

  • 按照Python C-API的编程规范,用C编写底层实现函数。
  • 用Python自带的disutils模块来管理编译、打包、生成Python模块。

所以后续的内容将主要围绕以上的方法来展开。

正文

编写C代码

假设要实现一个数学计算模块mymath,包含一个整数加法的函数add,那么首先要编写以下代码:

#include "D:\Anaconda2\include\Python.h"

/* file: mymath.c */

// 真正实现
int add(int a, int b)
{
    return a + b;
}

// 包装函数。Python调用add方法时传进来的参数在args里
PyObject* wrap_add(PyObject* self, PyObject* args)
{
    int a, b, result;
    // 解析参数
    if (!PyArg_ParseTuple(args, "ii", &a, &b))
        return NULL;
    result = add(a, b);
    // 返回PyObject* 类型的参数
    return Py_BuildValue("i", result);
}

// mymath模块所包含的函数列表
static PyMethodDef mymathMethods[] =
{
    // 每行一个方法,含义依次为
    // Python方法名,C方法名,参数值,方法文档
    {"add", wrap_add, METH_VARARGS, "doc: add(a, b) \nreturn a + b"},
    {NULL, NULL, 0, NULL}
    // 上面的最后一行相当于结束符
};

// 初始化模块的方法,自动调用
// 命名要求为init后加上模块名
void initmymath()
{
    PyObject* m;
    // 调用Py_InitModule方法初始化模块mymath,其中模块所具有
    // 的函数列表由第二个参数提供
    m = Py_InitModule("mymath", mymathMethods);
}

编译、打包与生成

在与mymath.c文件同级目录下编写setup.py文件,代码如下:

# file: setup.py
from distutils.core import setup, Extension

module1 = Extension('mymath',
                    sources = ['mymath.c'])

setup(name = 'mymath',
    version = '1.0',
    description = 'This is a Math package',
    ext_modules= [module1])


然后打开命令行窗口,进入到mymath.c所在目录,输入以下命令:

python setup.py build

可以看到以下输出信息:

编译、打包、生成时的输出信息.png

这个时候可以看到当前目录多了个build文件夹,一路进去可以看到mymath.pyd文件,这就是直接可调用的Python module了。继续在命令行里进入Python,可以直接调用mymath模块了

调用效果

参考资料

[1] Python/C API Reference Manual, https://docs.python.org/2/c-api/
[2] 《Python基础教程》(第2版)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • C++调用python 在C/C++中嵌入Python,可以使用Python提供的强大功能,通过嵌入Python可...
    Bruce_Szh阅读 13,838评论 1 7
  • # Python 资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列...
    aimaile阅读 26,579评论 6 427
  • 前言 Python的创始人为Guido van Rossum。1989年圣诞节期间,在阿姆斯特丹,Guido为了打...
    依依玖玥阅读 3,606评论 6 37
  • GitHub 上有一个 Awesome - XXX 系列的资源整理,资源非常丰富,涉及面非常广。awesome-p...
    若与阅读 18,757评论 4 418
  • 体验入: 圆满完成一年的日精进,总结持续一年来写日精进的收获好开心! 找核心: 1一切内求,永不计较! 2觉察问题...
    宇宙之爱黄昊贵阅读 288评论 0 1