我正在编写一个 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
...
Run Code Online (Sandbox Code Playgroud)
以及我想获得的分解代码类型:
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)
Run Code Online (Sandbox Code Playgroud)
在纯 Python 中,这种结构很容易使用globals
或来设置getattr
,但在 cython 中,cdef
对象(当然)无法从 python 访问,因此在globals()
.
我猜想C
这种代码的实现将使用函数指针,但我找不到如何在 cython 扩展类型中执行此操作。实际上,真正的问题是“是否可以添加指向 cdef 函数的指针作为实例属性(在 self 中)?如果不是,我怎样才能在不损失性能的情况下分解这种代码(即不改变我的 cdef 函数)?
您可以使用函数指针,但比纯 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)
Run Code Online (Sandbox Code Playgroud)
我不知道在运行时从函数名称获取 -function 指针的可能性cdef
,并且我不认为有一个现成的。
现在它的工作原理如广告所示:
>>> 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'
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1307 次 |
最近记录: |