到目前为止,我们关注的是从Python中可调用C函数。相反,从C中调用Python函数也是有用的。特别是在库支持回调函数的情况下。如果C接口使用回调,相应的,Python经常需要为Python 程序员提供回调机制;实现这种机制,将需要从C回调中调用Python回调函数。其他用法也可想像(Other uses are also imaginable)。
幸运的是,Python解释器容易递归调用,并且有一个标准的接口调用Python函数。(我不愿意总是惦记使用一个特别的字符串作为输入,调用Python解释器-除非你感兴趣,在Python源代码中看看Python/pythonmain.c 文件中-c命令行选项的实现)
调用Python函数是容易的,首先Python程序必须总是传递给你Python函数对象。你应该提供一个函数(或一些别的接口)处理它。当函数被调用时,保存Python函数对象指针(注意Py_INCREF())到一个全局变量-或你认为合适的地方。例如,下面函数也许是模块定义的一部分。
PyObject *arglist; PyObject *result; ... arg = 123; ... /* Time to call the callback */ arglist = Py_BuildValue("(i)", arg); result = PyEval_CallObject(my_callback, arglist); Py_DECREF(arglist);static PyObject *my_callback = NULL; static PyObject * my_set_callback(PyObject *dummy, PyObject *args) { PyObject *result = NULL; PyObject *temp; if (PyArg_ParseTuple(args, "O:set_callback", &temp)) { if (!PyCallable_Check(temp)) { PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; } Py_XINCREF(temp); /* Add a reference to new callback */ Py_XDECREF(my_callback); /* Dispose of previous callback */ my_callback = temp; /* Remember new callback */ /* Boilerplate to return "None" */ Py_INCREF(Py_None); result = Py_None; } return result; }
PyEval_CallObject()返回Python对象指针:这是Python函数的返回值。 PyEval_CallObject()函数对于每个参数是’引用计数无关’的,在这个例子中,新的元组为参数列表而建,在调用PyEval_CallObject()后立即调用Py_DECREF()。
PyEval_CallObject()函数返回值是’新建的’:或者是一个新对象,或者是一个引用计数已经被增加了的存在的对象。所以,除非你想把它保存在全局变量中,否则你总是调用用Py_DECREF()处理结果,无论(尤其是!)你是否关心它的值。
然而,在这么做(调用Py_DECREF)以前检查返回值是否为NULL很重要。如果返回值为NULL,Python函数由于产生异常被终止。如果调用PyEval_CallObject() 函数的C代码是从Python中调用的,现在它应该返回错误指示给Python调用者,这样解释器能够输出堆栈跟踪,或者调用者的Python代码能够处理异常。如果不可能或者想这么做,异常可以通过调用PyErr_Clear()来清除。例如:
if (result == NULL) return NULL; /* Pass error back */ ...use result... Py_DECREF(result);
根据Python回调函数想要的接口,你也许已经提供了参数列表给PyEval_CallObject()。有些情况下,参数列表也可由Python程序通过特定的回调函数接口提供。然后被以和功能对象同样的方式保存和使用。在其他情况下,你必须构造新的元组,作为参数列表传递。最简单的办法是调用Py_BuildValue(),例如,如果你向传递一个整数事件代码,你也许会使用下面的代码:
PyObject *arglist; ... arglist = Py_BuildValue("(l)", eventcode); result = PyEval_CallObject(my_callback, arglist); Py_DECREF(arglist); if (result == NULL) return NULL; /* Pass error back */ /* Here maybe use the result */ Py_DECREF(result);
注意在调用后立刻在错误检查前放置"Py_DECREF(arglist)" !还请注意:这段代码是不完整的: Py_BuildValue()函数可能会产生内存不足,这是应该检查的。