在前幾篇文章中,從一個較高的層次上說明了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.成員 , 而是直接用 類名.成員
本文的代碼可經過下面的連接下載: