如何用Python C API创建持有C函数指针的PyObject以调用Python函数
用Python C API将C函数包装为PyObject传给Python函数调用
核心思路
要让Python函数foo能调用你的C函数bar,得先把bar包装成符合Python调用规范的可调用对象,再打包成参数元组传给foo。
具体实现步骤
编写C包装函数
这个函数要遵循Python C API的签名规则,内部调用你的bar函数,最后返回Python的None:static PyObject* wrap_bar(PyObject* self, PyObject* args) { bar(); Py_RETURN_NONE; }定义方法描述结构体
告诉Python包装函数的参数类型等关键信息:static PyMethodDef bar_method_def = { "bar", // Python中显示的函数名 wrap_bar, // 对应的C包装函数指针 METH_NOARGS, // 标记该函数无参数 NULL // 文档字符串,可设为NULL };创建可调用的PyObject
基于上面的方法描述生成Python可调用对象:PyObject* bar_obj = PyCFunction_New(&bar_method_def, NULL); if (!bar_obj) { // 处理创建失败的情况,比如返回NULL或抛出异常 return NULL; }构建参数元组
因为foo需要一个参数,创建长度为1的元组并将bar_obj放入:PyObject* args = PyTuple_New(1); if (!args) { Py_DECREF(bar_obj); // 释放已分配的对象,避免内存泄漏 return NULL; } // PyTuple_SetItem会接管bar_obj的引用,无需手动调用Py_DECREF if (PyTuple_SetItem(args, 0, bar_obj) != 0) { Py_DECREF(args); Py_DECREF(bar_obj); return NULL; }调用Python函数
foo
将参数元组传入PyObject_Call完成调用:PyObject* function = PyObject_GetAttrString(module, "foo"); if (!function) { Py_DECREF(args); return NULL; } PyObject* result = PyObject_Call(function, args, NULL); // 释放不再使用的对象 Py_DECREF(function); Py_DECREF(args); if (!result) { // 处理调用失败的情况 return NULL; } // 使用完result后记得释放 Py_DECREF(result);
注意事项
- 所有创建的PyObject,在不再使用时必须用
Py_DECREF释放,防止内存泄漏。 - 每一步都要检查返回值是否为
NULL,及时处理异常场景。
内容的提问来源于stack exchange,提问作者Marko Devcic
相关产品推荐
相关产品推荐

