c语言函数封装成python库_『Python CoolBook』C扩展库_其五_C语言层面Python库之间调用API...

一、C层面模块添加API

我们仍然操作如下结构体,

#include

typedef struct Point {

double x,y;

} Point;

本节目标是封装两个Point结构体的操作函数为sample库的C级API,可以被sample以外的C库调用,首先写出以下函数指针结构体实例,

/* pysample.c */

static PyObject *PyPoint_FromPoint(Point *p, int must_free) {

/* 胶囊和C指针类似。在内部,它们获取一个通用指针和一个名称,可以使用

PyCapsule_New() 函数很容易的被创建。 另外,一个可选的析构函数能被

绑定到胶囊上,用来在胶囊对象被垃圾回收时释放底层的内存*/

return PyCapsule_New(p, "Point", must_free ? del_Point : NULL);

}

/* Utility functions */

static Point *PyPoint_AsPoint(PyObject *obj) {

return (Point *) PyCapsule_GetPointer(obj, "Point");

}

static _PointAPIMethods _point_api = {

PyPoint_AsPoint,

PyPoint_FromPoint

};

结构体定义如下,位于一个新的头函数中,

/* pysample.h */

/* Public API Table */

/* 这里最重要的部分是函数指针表 _PointAPIMethods.

它会在导出模块时被初始化,然后导入模块时被查找到。 */

typedef struct {

Point *(*aspoint)(PyObject *);

PyObject *(*frompoint)(Point *, int);

} _PointAPIMethods;

修改初始化函数,将函数指针结构体注册为Capsule,并将之使用PyModule_AddObject,添加给模块对象,作为模块属性,

PyModule_AddObject(PyObject *module, const char *name, PyObject *value),其中module就是Py_InitModule()返回的对象,含义就是将py_point_api这个类加入m这个模块中,并简记为"_point_api"。

/* pysample.c */

/* Module initialization function */

PyMODINIT_FUNC

PyInit_sample(void) {

PyObject *m;

PyObject *py_point_api;

m = PyModule_Create(&samplemodule);

if (m == NULL)

return NULL;

/* Add the Point C API functions */

py_point_api = PyCapsule_New((void *) &_point_api, "sample._point_api", NULL); //

if (py_point_api) {

PyModule_AddObject(m, "_point_api", py_point_api); //name略去模块名

}

return m;

}

测试如下,

不过由于Python并不能解析Capsule对象,所以这个API实际上是留给其他C源代码调用的。

我们希望在调用这个Capsule对象时,并不直接导入这个C源文件,只是使用头文件,所以我们在pysample.h中再进行一次封装,

/* pysample.h */

/* Method table in external module */

static _PointAPIMethods *_point_api = 0;

/* Import the API table from sample, import_sample() 被用来指向胶囊导入并初始化这个指针 */

static int import_sample(void) { //

// 需提供属性名(比如sample._point_api),会一次性找到胶囊对象并提取出指针来。

_point_api = (_PointAPIMethods *) PyCapsule_Import("sample._point_api",0); //

return (_point_api != NULL) ? 1 : 0;

}

/* Macros to implement the programming interface */

#define PyPoint_AsPoint(obj) (_point_api->aspoint)(obj)

#define PyPoint_FromPoint(obj) (_point_api->frompoint)(obj)

PyCapsule_Import:从模块中的capsule属性导入指向C对象的指针。 name 参数应指定属性的全名,如 module.attribute 中所示。存储在胶囊中的 name 必须与该字符串完全匹配。

此时我们就已经封装好了pysample.c中的两个函数为PyPoint_AsPoint和PyPoint_FromPoint,可以接受任何导入了pysample.h的文件使用。

小结

将函数指针封装到结构体中

将结构体生成为Capsule,并将其作为属性绑定给模块

使用PyCapsule_Import根据模块名称检索到Capsule,由于该函数会直接返回C指针,直接使用一个空的结构体接受Capsule即可

二、C层面模块调用API

/* ptexample.c */

/* Include the header associated with the other module */

#include "pysample.h"

/* An extension function that uses the exported API */

static PyObject *print_point(PyObject *self, PyObject *args) {

PyObject *obj;

Point *p;

if (!PyArg_ParseTuple(args,"O", &obj)) {

return NULL;

}

/* Note: This is defined in a different module */

p = PyPoint_AsPoint(obj);

if (!p) {

return NULL;

}

printf("%f %f\n", p->x, p->y);

return Py_BuildValue("");

}

static PyMethodDef PtExampleMethods[] = {

{"print_point", print_point, METH_VARARGS, "output a point"},

{ NULL, NULL, 0, NULL}

};

static struct PyModuleDef ptexamplemodule = {

PyModuleDef_HEAD_INIT,

"ptexample", /* name of module */

"A module that imports an API", /* Doc string (may be NULL) */

-1, /* Size of per-interpreter state or -1 */

PtExampleMethods /* Method table */

};

/* Module initialization function */

PyMODINIT_FUNC

PyInit_ptexample(void) {

PyObject *m;

m = PyModule_Create(&ptexamplemodule);

if (m == NULL)

return NULL;

/* Import sample, loading its API functions */

if (!import_sample()) { //

return NULL;

}

return m;

}

这里面先初始化前面.h文件中的指针,然后接收调用。

测试如下,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值