cpp extend python 的一种解决方案

来源:互联网 发布:淘宝安装服务在哪里找 编辑:程序博客网 时间:2024/04/29 15:05

因为python的module机制,python很容易通过c扩充。

官方的方法module,newType:http://docs.python.org/extending/index.html

ctype:http://docs.python.org/library/ctypes.html

但是cpp扩展python还是比较复杂,原因就是cpp的语法比较复杂。

比较好的现有解决方案就是:

boost.python:http://www.boost.org/doc/libs/1_48_0/libs/python/doc/

但是很多时候boost显得太笨重。对于我现在的需求并不合适。

我的基本思想:cpp其实算是用户定义的一个类型,自己提供constructor&destructor,

其实可以将cpp的一个class对应python的一个type。

例如:

在cpp中如下:

class CObject{    //…};

定义python的new type如下:

typedef struct {
PyObject_HEAD
CObject *pCObject;
} udt_CObject;

static PyObject* PyCObject_New(…)

{…}

static int PyCObject_Init(…)

{…}

static void PyCObject_free(udt_CObject* self)

{…}

static PyMethodDef CObject_Methods[] = {…}

static PyTypeObject CObject_Type = {…}

new type对象的构建有两种方式:

1、在cpp环境中创建(cpp嵌入python虚拟机的时候很有效):

udt_CObject*_CObject;
_CObject= (udt_CObject*)CObject_Type.tp_alloc(&CObject_Type, 0);

2、在python环境中创建,import你的动态库test,

object = test.CObject(…)

object.method…

用到的知识:

extending python with c or cpp:http://docs.python.org/extending/extending.html

defining new type:http://docs.python.org/extending/newtypes.html

理解C/CPP基本的编译链接。

注意的问题:

python GIL:多线程的环境下,如果c/cpp API里面有“阻塞”的系统调用,应该释放GIL。但是需要注意的问题是。

python环境传入c API环境的参数(这些对象),其实还是由python管理(其实想想这是合理滴)。Py_BEGIN_ALLOW_THREADS释放GIL

python虚拟机有可能回收这些memory,如果c API调用“引用”了这些地址就可能导致段错误。解决方案就是做适当的memcpy,用变量把传入的参数的“内容全部收下来“。

异常处理:基本要求就是python至少要知道cpp API调用进入到了exception 控制流。所以cpp API要捕获所有的cpp环境的异常。可以通过返回值或者riase exception,转换python定义的exception。但是这里有个需要主义的地方,如果想CPP环境抛出的exception被python环境捕获,你应该返回CPP的关键字NULL,而不是python关键字None。

返回值:建议用dict,这样容易扩充。

参数接受:最好不用size_t,这个数据类型导致很多兼容性问题。

总结C API要干的事情就是:接受python环境传入的参数,等待是释放GIL,处理返回值。

如果需要更加复杂点的解决方案但是又不想用boost.python,这是个不错的解决方案:http://www.python.org/doc/PyCPP.html