因为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。
返回值:建议用dict,这样容易扩充。
参数接受:最好不用size_t,这个数据类型导致很多兼容性问题。
总结C API要干的事情就是:接受python环境传入的参数,等待是释放GIL,处理返回值。
如果需要更加复杂点的解决方案但是又不能用boost.python
这是个不错的解决方案:http://www.python.org/doc/PyCPP.html