《扩展和嵌入python解释器》1.6 从C中调用Python函数

1.6 从C中调用Python函数

到目前为止,我们关注的是从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())到一个全局变量-或你认为合适的地方。例如,下面函数也许是模块定义的一部分。

 

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;
}

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);


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()函数可能会产生内存不足,这是应该检查的。  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值