围绕Python函数制作Cython包装器 [英] Making a Cython wrapper around Python function

查看:70
本文介绍了围绕Python函数制作Cython包装器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个C函数,其签名看起来像这样:

I have a C function which signature looks like this:

typedef double (*func_t)(double*, int)
int some_f(func_t myFunc);

我想将Python函数(不一定显式)作为some_f的参数传递。不幸的是,我负担不起更改some_f的声明,就是这样:我不应该更改C代码。

I would like to pass a Python function (not necessarily explicitly) as an argument for some_f. Unfortunately, I can't afford to alter declaration of some_f, that's it: I shouldn't change C code.

我试图做的一件显而易见的事情是创建一个基本包装函数是这样的:

One obvious thing I tried to do is to create a basic wrapping function like this:

cdef double wraping_f(double *d, int i /*?, object f */):
     /*do stuff*/
     return <double>f(d_t)

但是,我无法提出一种将其实际放置在wrapping_f体内的方法。

However, I can't come up with a way to actually "put" it inside wrapping_f's body.

这个问题有一个非常糟糕的解决方案:我可以使用一个全局对象变量,但是这迫使我将本质上相同的包装函数的多个实例复制-粘贴到粘贴实例中,这些实例将使用不同的全局函数(我打算同时使用多个Python函数)。

There is a very bad solution to this problem: I could use a global object variable, however this forces me copy-n-paste multiple instances of essentially same wrapper function that will use different global functions (I am planning to use multiple Python functions simultaneously).

推荐答案

出于历史原因,我保留了其他答案-这表明,不进行jit编译就无法做您想要的事情,并且可以帮助我了解@DavidW的出色表现在这个答案是。

I keep my other answer for historical reasons - it shows, that there is no way to do what you want without jit-compilation and helped me to understand how great @DavidW's advise in this answer was.

为简单起见,我使用了一个稍微简单的签名函数并相信您可以根据需要进行更改。

For the sake of simplicity, I use a slightly simpler signature of functions and trust you to change it accordingly to your needs.

以下是闭包的蓝图,它允许 ctypes 在后台进行jit编译:

Here is a blueprint for a closure, which lets ctypes do the jit-compilation behind the scenes:

%%cython
#needs Cython > 0.28 to run because of verbatim C-code 
cdef extern from *:   #fill some_t with life
    """
    typedef int (*func_t)(int);
    static int some_f(func_t fun){
        return fun(42);
    }
    """
    ctypedef int (*func_t)(int)
    int some_f(func_t myFunc)

#works with any recent Cython version:
import ctypes
cdef class Closure:
    cdef object python_fun
    cdef object jitted_wrapper

    def inner_fun(self, int arg):
        return self.python_fun(arg)

    def __cinit__(self, python_fun):
        self.python_fun=python_fun
        ftype = ctypes.CFUNCTYPE(ctypes.c_int,ctypes.c_int) #define signature
        self.jitted_wrapper=ftype(self.inner_fun)           #jit the wrapper

    cdef func_t get_fun_ptr(self):
        return (<func_t *><size_t>ctypes.addressof(self.jitted_wrapper))[0]

def use_closure(Closure closure):
    print(some_f(closure.get_fun_ptr()))

现在使用它:

>>> cl1, cl2=Closure(lambda x:2*x), Closure(lambda x:3*x)
>>> use_closure(cl1)
84
>>> use_closure(cl2)
126

这篇关于围绕Python函数制作Cython包装器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆