从 C 调用Python |设置 1
在本文中,我们将主要关注从 C 调用Python的安全执行、将结果返回给 C 以及编写需要访问Python函数作为回调的 C 代码。
下面的代码重点介绍了从 C 调用Python所涉及的棘手部分。
代码 #1 : [步骤 1 和 2] 拥有 GIL 并验证该函数是正确的可调用函数
#include
/* Execute func(x, y) in the Python interpreter. The
arguments and return result of the function must
be Python floats */
double call_func(PyObject *func, double x, double y)
{
PyObject *args;
PyObject *kwargs;
PyObject *result = 0;
double retval;
// Make sure we own the GIL
PyGILState_STATE state = PyGILState_Ensure();
// Verify that func is a proper callable
if (!PyCallable_Check(func))
{
fprintf(stderr, "call_func: expected a callable\n");
goto fail;
}
代码 #2:构建参数、调用函数、检查Python异常
创建返回值,恢复之前的 GIL 状态并返回。
// Step3
args = Py_BuildValue("(dd)", x, y);
kwargs = NULL;
// Step 4
result = PyObject_Call(func, args, kwargs);
Py_DECREF(args);
Py_XDECREF(kwargs);
// Step 5
if (PyErr_Occurred())
{
PyErr_Print();
goto fail;
}
// Verify the result is a float object
if (!PyFloat_Check(result))
{
fprintf(stderr, "call_func: callable didn't return a float\n");
goto fail;
}
// Step 6
retval = PyFloat_AsDouble(result);
Py_DECREF(result);
// Step 7
PyGILState_Release(state);
return retval;
fail:
Py_XDECREF(result);
PyGILState_Release(state);
abort();
}
需要传入对现有Python可调用对象的引用才能使用此函数。要做到这一点,有很多方法,比如简单地编写 C 代码以从现有模块中提取符号或将可调用对象传递给扩展模块。下面给出的代码显示了从嵌入式Python解释器调用函数。
代码#3:从模块加载符号
#include
/* Definition of call_func() same as above */
/* Load a symbol from a module */
PyObject *import_name(const char *modname, const char *symbol)
{
PyObject *u_name, *module;
u_name = PyUnicode_FromString(modname);
module = PyImport_Import(u_name);
Py_DECREF(u_name);
return PyObject_GetAttrString(module, symbol);
}