点击进入项目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