【问题标题】:Function pointer in cython extension typecython 扩展类型中的函数指针
【发布时间】:2019-04-30 10:16:35
【问题描述】:

我正在编写一个 cython 模块,它提供了几种使用优化的cdef 函数的扩展类型。其中几个扩展类型(大约 10 个,每个包含大约 200 行代码)具有完全相同的结构,但不调用相同的 cdef 函数。我想分解我的模块,以便只有一种扩展类型可以处理我需要的所有不同配置。

为了更清楚地说明这一点,这是我正在编写的模块结构的一个(非常愚蠢的)示例:

cdef class A1:

    cdef double x

    def __init__(self, double x):
        self.x = x

    def apply(self):
        self.x = f1(self.x)

cdef class A2:

    cdef double x

    def __init__(self, double x):            
        self.x = x

    def apply(self):
        self.x = f2(self.x)       

cdef double f1(double x):
    return x**1

cdef double f2(double x):
    return x**2

...

以及我想获得的分解代码:

cdef class A:

    cdef int n
    cdef double x

    def __init__(self, double x, int n):
        self.x = x
        self.f = globals()[f'f{n}']

    def apply(self):
        self.x = self.f(self.x)

在纯 Python 中,这种结构很容易使用 globalsgetattr 设置,但在 cython 中,cdef 对象(当然)无法从 python 访问,因此在 globals() 中无法访问。

我猜这种代码的C 实现会使用函数指针,但我找不到如何在 cython 扩展类型中执行此操作。实际上真正的问题是'是否可以将指向 cdef 函数的指针添加为实例属性(在自身中)?如果没有,我怎样才能在不损失性能的情况下分解这种代码(即不改变我的 cdef 函数)?

【问题讨论】:

    标签: python cython


    【解决方案1】:

    你可以使用函数指针,但样板代码比纯 python 多一点,例如:

    %%cython
    
    # here all possible functions double->double
    cdef double fun1(double x):
        return 2*x
    
    cdef double fun2(double x):
        return x*x;
    ...
    
    # class A wraps functions of type double->double
    ctypedef double(*f_type)(double) 
    
    # boiler-plate code for obtaining the right functor
    # uses NULL to signalize an error
    cdef f_type functor_from_name(fun_name) except NULL:
        if fun_name == "double":
            return fun1
        elif fun_name == "square":
            return fun2
        else:
            raise Exception("unknown function name '{0}'".format(fun_name)) 
    
    
    cdef class A:
        cdef f_type fun
    
        def __init__(self, fun_name ):
            self.fun = functor_from_name(fun_name)
    
        def apply(self, double x):
            return self.fun(x)
    

    我不知道有可能在运行时从函数名称中获取cdef-function 指针,而且我认为没有现成可用的指针。

    现在它可以像宣传的那样工作了:

    >>> doubler = A("double")
    >>> double.apply(3.0)
    6.0
    >>> squarer = A("square")
    >>> squarer.apply(3.0)
    9.0
    >>> dummy = A("unknown")
    Exception: unknown function name 'unknown'
    

    【讨论】:

    • 太棒了!少了 500 行 :) 谢谢
    猜你喜欢
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 2019-05-27
    • 2015-01-05
    相关资源
    最近更新 更多