點擊進入項目git
C語言中的結構體傳給Python時會被封裝爲膠囊(Capsule),程序員
咱們想要一個以下結構體進行運算,則須要Python傳入x、y兩個浮點數,github
typedef struct Point { double x,y; } Point;
而後對這兩個浮點數解析後生成C中Point的結構體,以下,函數
/* Create a new Point object */ static PyObject *py_Point(PyObject *self, PyObject *args) { Point *p; double x,y; if (!PyArg_ParseTuple(args,"dd",&x,&y)) { return NULL; } p = (Point *) malloc(sizeof(Point)); p->x = x; p->y = y; return PyPoint_FromPoint(p, 1); }
上面最後一句將使用C中的結構體構建Python膠囊對象並返回給Python,工具
/* Destructor function for points */ static void del_Point(PyObject *obj) { free(PyCapsule_GetPointer(obj,"Point")); } static PyObject *PyPoint_FromPoint(Point *p, int must_free) { /* 膠囊和C指針相似。在內部,它們獲取一個通用指針和一個名稱,能夠使用 PyCapsule_New() 函數很容易的被建立。 另外,一個可選的析構函數能被 綁定到膠囊上,用來在膠囊對象被垃圾回收時釋放底層的內存*/ return PyCapsule_New(p, "Point", must_free ? del_Point : NULL); }
PyCapsule_New():從結構體建立膠囊ui
PyCapsule_GetPointer()
:提取膠囊中的指針,使用 PyCapsule_GetPointer()
函數並指定名稱。 若是提供的名稱和膠囊不匹配或其餘錯誤出現,那麼就會拋出異常並返回NULL。實際上就是從膠囊轉換回結構體spa
效果以下,設計
>>> import sample >>> p1 = sample.Point(2,3) >>> p2 = sample.Point(4,5) >>> p1 <capsule object "Point" at 0x1004ea330> >>> p2 <capsule object "Point" at 0x1005d1db0>
本節中,一對工具函數—— PyPoint_FromPoint()
和 PyPoint_AsPoint()
被用來建立和從膠囊對象中提取Point實例。 在任何擴展函數中,咱們會使用這些函數而不是直接使用膠囊對象。 這種設計使得咱們能夠很容易的應對未來對Point底下的包裝的更改。 例如,若是你決定使用另一個膠囊了,那麼只須要更改這兩個函數便可。3d
對於膠囊對象一個難點在於垃圾回收和內存管理。 PyPoint_FromPoint()
函數接受一個 must_free
參數, 用來指定當膠囊被銷燬時底層Point * 結構體是否應該被回收。 在某些C代碼中,歸屬問題一般很難被處理(好比一個Point結構體被嵌入到一個被單獨管理的大結構體中)。 程序員能夠使用 extra
參數來控制,而不是單方面的決定垃圾回收。 要注意的是和現有膠囊有關的析構器能使用 PyCapsule_SetDestructor()
函數來更改。指針
/* Utility functions */ static Point *PyPoint_AsPoint(PyObject *obj) { return (Point *) PyCapsule_GetPointer(obj, "Point"); } static PyObject *py_distance(PyObject *self, PyObject *args) { Point *p1, *p2; PyObject *py_p1, *py_p2; double result; if (!PyArg_ParseTuple(args,"OO",&py_p1, &py_p2)) { return NULL; } if (!(p1 = PyPoint_AsPoint(py_p1))) { return NULL; } if (!(p2 = PyPoint_AsPoint(py_p2))) { return NULL; } result = distance(p1,p2); return Py_BuildValue("d", result); }
將兩個結構體轉爲C指針存儲後,分別使用PyCapsule_GetPointer()
提取指針信息轉換爲結構體,計算後返回。
>>> sample.distance(p1,p2) 2.8284271247461903