Skip to main content
 Web开发网 » 编程语言 » Python语言

如何用Python写C扩展?

2021年11月27日6630百度已收录

一般来说,Python扩展C,有三种方式,来实现加速,以下通过Python2.7,minw32 3.82.90,windows 7 进行说明。

一、ctypes

ctypes使用c函数,需要先将c编译成动态链接库,即.dll文件。

举个简单的栗子,c文件 examples.c:

#include <stdio.h>

int show_me_the_money(int m) {

printf("Money is %d\n", m);

return m;

编译成动态链接库:

mingw32-gcc examples.c -o examples.dll -shared通过ctypes调用show_me_the_money这个函数:

#coding: utf-8

import ctypes

lib = ctypes.cdll.LoadLibrary("examples.dll")

lib.show_me_the_money(100)

结果是:

Money is 100

ctypes方式简单易用,只要动态库不涉及线程操作,交互的数据结构不复杂,特别是动态链接库已经有了,推荐使用。ctypes的详细细节可参考官方文档。

二、c extension方式

python c extension也是一种动态链接库,与一般的dll文件相比,它有两点不同

要实现一个PyMODINIT_FUNC函数,函数名称为 init模块名,比如你的模块名是pyTEST,那么这个函数名称就是 initpyTEST

文件后缀为.pyd

Enough talk, let's fight!

pyTEST.c:

#include <Python.h>

#include <Windows.h>

static PyObject *

get_version(PyObject *self, PyObject *args)

return Py_BuildValue("s", "1.0");

static PyMethodDef module_methods[] = {

{"get_version", get_version, METH_VARARGS, "Get module version"},

{NULL, NULL, 0, NULL} /*Sentinel */

PyMODINIT_FUNC

initpyTEST(void)

PyObject *m;

m = Py_InitModule3("pyTEST", module_methods, "An example demostrates how python c extensions implement and work.");

if (m == NULL) return;

编译:

mingw32-gcc -I./python/include -c pyTEST.c -o pyTEST.o链接:

mingw32-gcc -shared -o pyTEST.pyd pyTEST.o -lpython27 -L./python/libs测试脚本

#coding: utf-8

import pyTEST

print pyTEST.get_version()

执行结果

1.0

这种方式的c扩展有许多细节需要注意,比如引用计数的增减处理(Py_INCREF, Py_DECREF等宏的使用),处理错误就会造成内存泄漏或者非法内存访问,需要对borrowing references和new references有清晰的概念。

咱们来个栗子,做个测试,改一下get_version:

static PyObject *

get_version(PyObject *self, PyObject *args)

PyObject *ret = Py_BuildValue("s", "1.0");

Py_DECREF(ret);

return ret;

再修改测试脚本:

#coding: utf-8

import pyTEST

import gc

v = pyTEST.get_version()

print v

gc.collect()

print "here, %s" % v

你就会发现Python挂了并提示:Fatal Python error:deletion of interned string failed。这其中有许多细节,比如返回的类型不同,结果也不同,大家可以自行测试。

三、SIP,Boost.Python, SWIG, Cython, Pybindgen

sip是Qt移植到python过程中开发的,wxWidget也有大量使用;cython一般多用于科学计算领域的加速。

这方面本人应用用的不多,就不在此误人子弟。期待高手们解答,分享经验。

评论列表暂无评论
发表评论
微信