首页 > 解决方案 > Cython:如何制作具有不同签名的函数数组

问题描述

在 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

标签: pythonpython-3.xcythonfunction-pointers

解决方案


我想不出你可以用一组未知类型的函数指针做任何有用的事情——调用它们是不安全的(因为你不知道签名),而且真的没有任何其他事情可做函数指针。因此,您至少需要找到某种方法来存储它是什么类型的指针。

一种选择是存储一个包含两个指针的结构:

cdef struct FuncPtrStruct:
    func2param f2p
    func3param f3p

然后将一个设置为NULL,存储在另一个中,并且只调用非NULL一个 数组规范将类似于cdef FuncPtrStruct array[10]

但是,我可能会使用 C Union 来将两个指针存储在同一个内存位置(+ 一个枚举来标识类型)。这需要更多的努力来设置(您需要enum定义 的类型unionunion本身,以及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

只是为了说明您将如何使用它:

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)

看起来您的代码中有一些listPython 对象,这就是您遇到编译错误的原因。没有代码就不可能知道为什么,但我认为 Cython 可以自动为cdef函数生成 Python 包装器,所以我猜你已经以某种方式列出了这些包装器。如果您想处理 Python 列表FuncPtrHolder(或以其他方式从 Python 中使用它),您必须将其包装在cdef class.


在这种情况下,我首选的更简单的解决方案可能是只使用func3param并让“双参数”函数简单地忽略第三个参数。这意味着所有函数指针都将具有一致的签名,这对我来说更有意义。


推荐阅读