在Cython中,我想存储一个函数数组,但是这些函数并不都具有相同的签名。具体来说,有些具有两个参数,另一些具有三个。
我定义了以下内容:
ctypedef long (*func2param)(long param1, long param2)
ctypedef long (*funct3param)(long param1, long param2, long param3)
但是,即使我只有一个这样的签名,我仍然不确定如何使它起作用。尝试将cdef函数分配给上述类型之一的数组会给我:
func_array2[i] = func_list[i][FUNCTION]
Cannot convert Python object to 'func2param'
尝试投射会给出:
func_array2[i] = <func2param>func_list[i][FUNCTION]
Python objects cannot be cast to pointers of primitive types
答案 0 :(得分:3)
我想不出对未知类型的函数指针数组可以做的有用的事情-调用它们是不安全的(因为您不知道签名),实际上什么也没有与函数指针有关。因此,您至少需要找到某种存储指针类型的方法。
一种选择是存储包含两个指针的结构:
cdef struct FuncPtrStruct:
func2param f2p
func3param f3p
然后将一个设置为NULL
,存储在另一个中,然后仅调用非NULL
。然后,数组规范将类似于cdef FuncPtrStruct array[10]
。
但是,我可能会改用C联合将两个指针存储在同一内存位置(+一个枚举来标识类型)。设置起来需要付出更多的努力(您需要一个enum
来定义union
的类型,union
本身以及一个包含{{1 }}和struct
);但是优点是您可以添加更多不同类型的函数指针而无需使用更多内存(对于“两种类型”情况,内存可能相等):
enum
仅说明您的用法:
union
在您的代码中似乎您有一些# cpdef if you want to use the enum from Python too
cdef enum FuncType:
twoArg, threeArg
cdef union FuncPtrUnion:
func2param f2p
func3param f3p
cdef struct FuncPtrHolder:
FuncType type_
FuncPtrUnion value
的Python对象,这就是为什么您遇到编译错误的原因。没有代码,就不可能知道为什么,但是我认为Cython可以自动为cdef long f(long x1, long x2):
print("f",x1,x2)
return 0
cdef long g(long x1, long x2, long x3):
print("g",x1,x2,x3)
return 1
def example():
cdef FuncPtrHolder fArray[10]
for i in range(10):
if i%2:
fArray[i].type_ = twoArg
fArray[i].value.f2p = &f
else:
fArray[i].type_ = threeArg
fArray[i].value.f3p = &g
# use
for i in range(10):
if fArray[i].type_ == twoArg:
fArray[i].value.f2p(i,i+1)
elif fArray[i].type_ == threeArg:
fArray[i].value.f3p(i,i+1,i+2)
函数生成Python包装器,因此我想您已经以某种方式列出了这些包装器。如果要处理list
的Python列表(或从Python使用它),则必须将其包装在cdef
中。
在这种情况下,我的首选,更简单的解决方案可能是只使用FuncPtrHolder
并让“两个参数”函数简单地忽略第三个参数。这意味着所有函数指针都将具有一致的签名,这对我来说更有意义。