如何将Python函数作为参数传入C/C++扩展实现的Python函数
错误原因
你解析得到的f_py是Python函数对象在C层面的指针,并非原生C函数指针,不能直接用C的f_py(5)语法调用,必须通过Python C API提供的调用接口完成函数调用、返回值解析操作。
正确实现代码
修改后的f_cpp函数如下:
static PyObject* f_cpp(PyObject* self, PyObject* args) { PyObject* f_py; if (!PyArg_ParseTuple(args, "O", &f_py)) { return NULL; } // 校验传入的对象是否是可调用类型 if (!PyCallable_Check(f_py)) { PyErr_SetString(PyExc_TypeError, "parameter must be a callable function"); return NULL; } // 调用Python函数,传入整数参数5 PyObject* ret = PyObject_CallFunction(f_py, "i", 5); // 检查函数调用是否出错 if (ret == NULL) { return NULL; } // 将Python返回的浮点数转为C的double类型 double x = PyFloat_AsDouble(ret); // 检查类型转换是否出错 if (PyErr_Occurred()) { Py_DECREF(ret); return NULL; } // 释放返回值的引用,避免内存泄漏 Py_DECREF(ret); // 执行自定义C函数逻辑并返回结果 return PyFloat_FromDouble(f(x)); }
关键逻辑说明
PyCallable_Check用于校验传入的对象是否是可调用类型,避免传入非函数对象时程序崩溃PyObject_CallFunction是Python提供的C API,用于调用Python可调用对象,第二个参数为参数格式符,"i"表示后续传入一个C int类型作为Python函数的参数- 调用Python函数得到的返回值是
PyObject*类型,需要通过PyFloat_AsDouble转换为C语言原生的double类型 - 所有通过Python C API生成的新对象(这里指
ret)使用完成后必须调用Py_DECREF减少引用计数,避免内存泄漏
内容的提问来源于stack exchange,提问作者Sergey Revkov
相关产品推荐
相关产品推荐

