简体   繁体   English

Python / Cython / C和回调,使用Cython从C调用Python函数

[英]Python/Cython/C and callbacks, calling a Python function from C using Cython

I have the following question. 我有以下问题。 We have to pass callback functions to the C code. 我们必须将回调函数传递给C代码。 If the function is a Cython function in the same module, the situation is quite simple 如果该函数是同一模块中的Cython函数,则情况非常简单

In Cython: 在Cython中:

def callme(int x):
    c_callme(x, <int (*)(int)>&callbackme) 

cdef int callbackme(int x):
    print <int> x
    return <int>x

In C: 在C:

int c_callme(int x, int (*f)(int))
{
    printf("---%d\n",x);
    printf("--%d\n",f(x));
    return x;
}

The question is as follows: we want to generalize this code in the most Pythonic way so that it can accept also python functions as callback arguments (of course, some additional layer is needed), and also C/Cython functions from another module. 问题如下:我们希望以最Pythonic方式推广这些代码,以便它也可以接受python函数作为回调参数(当然,还需要一些额外的层),以及来自另一个模块的C / Cython函数。 I suppose, for C/Cython functions from a separate module one has to get the address of these functions (convert to long int?) and for Python function a certain wrapper is needed 我想,对于来自单独模块的C / Cython函数,必须获取这些函数的地址(转换为long int?),对于Python函数,需要某个包装器

In this example, extracted from a Python wrapper to the Cubature integration C library , a Python function is passed to a C function that has the prototype given by cfunction . 在这个例子中, 从Python包装器提取Cubature集成C库 ,Python函数被传递给C函数,该函数具有由cfunction给出的原型。 You can create a function with the same prototype, called cfunction_cb (callback), and returning the same type, int in this example): 您可以使用相同的原型创建一个函数,称为cfunction_cb (回调),并返回相同的类型,在此示例中为int ):

cdef object f
ctypedef int (*cfunction) (double a, double b, double c, void *args)

cdef int cfunction_cb(double a, double b, double c, void *args):
    global f
    result_from_function = (<object>f)(a, b, c, *<tuple>args)
    for k in range(fdim):
        fval[k] = fval_buffer[k]
    return 0

When calling the C function, you can cast your callback wrapper using the C prototype: 调用C函数时,可以使用C原型强制转换回调包装:

def main(pythonf, double a, double b, double c, args): 
    global f
    f = pythonf
    c_function( <cfunction> cfunction_cb,
                double a,
                double b,
                double c,
                <void *> args )

In this example it is also shown how to pass arguments to your Python function, through C. 在这个例子中,还展示了如何通过C将参数传递给Python函数。

I think the easiest way would be to wrap C callbacks in 我认为最简单的方法是将C回调包装进去

cdef class Callback(object):
    cdef int (*f)(int)        # I hope I got the syntax right...

    def __call__(int x):
        return self.f(x)

so you can pass objects of this type, as well as any other callable, to the function that must call the callback. 因此,您可以将此类型的对象以及任何其他可调用对象传递给必须调用回调的函数。

However, if you must call the callback from C, then you should may pass it an extra argument, namely the optional address of a Python object, perhaps cast to `void*. 但是,如果你必须从C调用回调,那么你应该传递一个额外的参数,即Python对象的可选地址,可能转换为`void *。

(Please do not cast function pointers to long , or you may get undefined behavior. I'm not sure if you can safely cast a function pointer to anything, even void* .) (请不要投函数指针long ,或者你可能会得到未定义的行为。我不知道你是否能安全地转换函数指针到任何东西,甚至void* )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM