cython扩展类型的功能指针 [英] Function pointer in cython extension type

查看:125
本文介绍了cython扩展类型的功能指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing a cython module that provides several extension types that use optimized cdef functions. Several of these extension types (about 10, each containing about 200 lines of code) have exactly the same structure but don't call the same cdef functions. I would like to factorize my module so that only one extension type can handle all the different configurations I need.

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

To make this clearer, here is a (very silly) example of the structure of the module I'm writing :

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

...

我想获得的分解代码的类型:

and the kind of factorized code I would like to obtain :

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中,这种结构是易于使用 globals getattr 进行设置,但是在cython cdef 对象(当然)不能从python访问,所以在 globals()中不是。

In pure Python, this kind of structure is easy to setup using globals or getattr, but in cython cdef objects are (of course) not accessible from python, so not in globals().

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

I guess that a C implementation of this kind of code would use function pointers but I can't find how to do this inside an cython extension type. Actually the real question is 'is it possible to add a pointer to a cdef function as an instance attribute (in self) ? If not, how can I factorize this kind of code without losing performances (i.e. without changing my cdef functions) ?

推荐答案

使用函数指针,但是比纯python中的样板代码要多一些,例如:

You could use function pointer, but with a little bit more boilerplate code than in pure python, for example:

%%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指针,我不认为

I'm not aware of a possibility to get cdef-function pointer from the name of the function at run time and I don't think there is one out-of-the-box.

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

And now it works as advertised:

>>> 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'

这篇关于cython扩展类型的功能指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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