在前几篇文章中,从一个较高的层次上说明了SWIG的基本用法。这篇文章会深刻到SWIG的一些实现的细节中。SWIG默认的封装方式,是把C/C++的struct和class封装到Python Proxy Class中。不过从SWIG 2.0.4开始, swig提供了一个新的参数-builtin, 这种封装的方式比Python Proxy Class更高效。python
Python Proxy Class是SWIG封装的一个很关键的部分。Python Proxy Class提供了一个很天然的访问C/C++代码的方式,从而能提供不少SWIG的特性。假如你有这样一段C++的代码:app
class Foo { public: int x; int spam(int); ...
SWIG会把这个类的成员变量和成员函数,封装成一些简单的函数。例如在foo_wrap.cxx中会有一个_wrap_new_Foo这个函数是对于new Foo的封装。在这个函数中,先会动态分配一个Foo对象,而后将这个对象包裹在SwigPyObject对象内,最后将这个SwigPyObject的对象返回。函数
/* Foo *new_Foo() { return new Foo(); } */ SWIGINTERN PyObject *_wrap_new_Foo(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0; Foo *result = 0 ; if (!PyArg_ParseTuple(args,(char *)":new_Foo")) SWIG_fail; result = (Foo *)new Foo(); resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Foo, SWIG_POINTER_NEW | 0 ); return resultobj; fail: return NULL; }
在生成的python接口中,在python proxy class Foo 内部其实就是调用wrap_new_foo这个函数来生成一个新的SwigPyObject对象,而且把原生的Foo对象的指针包裹在本身的内部:ui
class Foo(_object): def __init__(self): this = _foo.new_Foo() try: self.this.append(this) except: self.this = this
从Python Proxy Class的细节中,咱们能够知道,一个Python对象调用原生的C++对象,其实是3层封装:this
1 Python对象包含SwigPyObjectspa
2 SwigPyObject包含原生的C++的Foo对象指针
3 原生的C++的Foo对象code
层次越多效率越低,为此在swig 2.0.4以后推出了一个Buitin type的特性。利用这个特性实现的Python类,能够越过SwigPyObject这一层,直接包含原生的C++的Foo对象。经过减小封装的层次,提升代码的执行效率。对象
咱们能够采用swig -builtin这个参数来激活这个特性。接口
经过swig -builtin参数生成的 wrap源代码中有这样的定义:
SWIGINTERN PyMethodDef SwigPyBuiltin__Foo_methods[] = { { "bar", (PyCFunction) _wrap_Foo_bar, METH_VARARGS, (char*) "" }, { NULL, NULL, 0, NULL } /* Sentinel */ }; static PyHeapTypeObject SwigPyBuiltin__Foo_type = { /* 省略成员的定义 */ }
定义了一种新的python builtin类型 Foo_type,在python中,能够直接调用Foo_type来操纵Foo*。
不过使用Builtin 特性有一些要注意的点:
1 python 2.3以前的版本不支持
2 不能直接调用函数接口,好比new_foo这样的函数,而是直接调用Foo()
3 对象的静态成员不须要用 .cvar.成员 , 而是直接用 类名.成员
本文的代码可经过下面的连接下载: