Python扩展模块中的 C API |设置 1
假设给定一个 C 扩展模块,该模块在内部定义了各种有用的函数,这些函数可以导出为公共 C API 以在其他地方使用。现在,如果我们想在其他扩展模块中使用这些功能。然后,知道如何将它们链接在一起很重要,但使用 C 编译器/链接器进行链接似乎过于复杂。
代码 #1 : [C 代码] 点对象,包括一些实用功能
# Destructor function for points
static void del_Point(PyObject *obj)
{
free(PyCapsule_GetPointer(obj, "Point"));
}
static PyObject *PyPoint_FromPoint(Point *p, int must_free)
{
return PyCapsule_New(p, "Point", must_free ? del_Point : NULL);
}
# Utility functions
static Point *PyPoint_AsPoint(PyObject *obj)
{
return (Point *) PyCapsule_GetPointer(obj, "Point");
}
现在,要处理的问题是如何将PyPoint_AsPoint()
和PyPoint_FromPoint()
函数的导出处理为可供其他扩展模块使用并可以链接到其他扩展模块的 API。 (例如——任何其他扩展也想使用包装的 Point 对象)。
代码 #2:为work
扩展引入一个名为Pythonsample.h
的新头文件。
//pythonsample.h
#include "Python.h"
#include "work.h"
#ifdef __cplusplus
extern "C" {
#endif
// Public API Table
typedef struct
{
Point *(*aspoint)(PyObject *);
PyObject *(*frompoint)(Point *, int);
} _PointAPIMethods;
#ifndef PYTHONSAMPLE_MODULE
/* Method table in external module */
static _PointAPIMethods *_point_api = 0;
代码#3:从“work”导入API表
static int import_sample(void)
{
_point_api = (_PointAPIMethods *) PyCapsule_Import("work._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)
#endif
#ifdef __cplusplus
}
#endif
_PointAPIMethods函数指针表是最重要的功能,因为它将在导出模块中初始化并通过导入模块找到。下面的代码显示了如何更改原始扩展模块以填充表格并将其导出。
代码#4:析构函数和实用函数
// pythonsample.c
# include "Python.h"
# define PYTHONSAMPLE_MODULE
# include "pythonsample.h"
// Destructor function for points
static void del_Point(PyObject * obj)
{
printf("Deleting point\n");
free(PyCapsule_GetPointer(obj, "Point"));
}
// Utility functions
static Point * PyPoint_AsPoint(PyObject * obj)
{
return (Point *) PyCapsule_GetPointer(obj, "Point");
}
static PyObject * PyPoint_FromPoint(Point * p, int free)
{
return PyCapsule_New(p, "Point", free ? del_Point : NULL);
}
static _PointAPIMethods _point_api =
{
PyPoint_AsPoint,
PyPoint_FromPoint
};
代码#5:模块函数
// 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, "work._point_api", NULL);
if (py_point_api)
{
PyModule_AddObject(m, "_point_api", py_point_api);
}
return m;
}