Cython - 将指针数组转换为Python对象
好的,我快要完成这个项目了,感觉已经触手可及了。在过去的几周里,我一直在尝试创建一个Python扩展,用来通过Cython与一个用C++写的库进行交互。在这里得到了一些帮助,还有几个朋友的支持,我觉得自己已经完成了大约98%的工作。剩下的唯一问题是:我实在搞不懂怎么把一个指向无符号短整型数组的指针转换成Python对象(最好是列表)。
先说一下背景,我正在尝试与库中的一个设置回调函数的部分进行交互,这个我已经成功实现了,代码如下:
global callbackfunc
ctypedef unsigned short const_ushort "const uint16_t"
ctypedef void (*Function1)(const_ushort *data, unsigned width, unsigned height)
cdef extern from "lib.hpp":
void SetCallback(Function1)
cdef void cSetCallback(Function1 function):
SetCallback(function)
cdef void callcallback(const_ushort *data, unsigned width, unsigned height):
global callbackfunc
callbackfunc(data,width,height)
cSetCallback(callcallback)
def PySetCallback(callbackFunc):
global callbackfunc
callbackfunc = callbackFunc
问题出现在“callcallback”这个函数里,我遇到了一个错误:“无法将'const_ushort *'转换为Python对象”。我第一次尝试解决这个问题时,创建了一个新的Python列表,然后循环遍历数组,把每个元素放到Python列表里,像这样:
datalist = []
for i in range(width*height):
datalist += data[i]
但是,结果是编译的Cython代码试图把一个类型定义为“const const unsigned short”,这显然是个问题。
接着我尝试了这个:
datalist = []
for i in data:
datalist += i
结果提示我“C数组迭代需要已知的结束索引”。需要说明的是,我对C/C++了解得很少,所以大部分内容对我来说并不太明白。
总之,有没有什么有效的方法可以把这样的指针转换成Python对象(最好比循环遍历数组快,因为通常有大约57344个项目,而且这个过程对时间要求很高)
编辑: 再多说一点,正如我提到的,我在处理回调,而库中的C++函数会发送一个指向“const uint_16”数组的指针,这就是我这样定义const_ushort的原因,因为否则类型就不一致了。我无法以任何方式修改这个库。
编辑2: 看起来我搞定了。最后我不得不明确将数组转换为无符号短整型数组,而不是常量无符号短整型数组,这样我才能用非常量来索引它们。为此,我创建了另一个C++函数,像这样(是别人帮我写的,我对C++几乎一无所知):
unsigned short *convert_short(const unsigned short *test){ return const_cast<unsigned short *>(test); }
这让我在我的类中创建了“getindex”函数,并根据这个函数返回正确的值。所以,Python似乎能够正确读取这些数组,问题看起来解决了。非常感谢大家。
2 个回答
这可能不是你想问的,但如果你想在Cython中处理一个无符号短整型数组,然后让这个结果在Python中使用,你可以在Python那边创建一个Numpy的ndarray,然后把它传到Cython里。在Cython中,这个ndarray大致上就像一个多维数组。这样,你就能享受到Python的内存管理、方便的索引语法,以及在Cython中处理真实数组的速度。
这里有一个来自我Project Euler解决方案的例子。
ctypedef unsigned short const_ushort "const uint16_t"
这段话的意思是,使用 const
会让它在 C 代码中出现,所以你会看到 typedef unsigned short const uint16_t
,但这里的 const
其实没有什么意义。(而且它还重新定义了标准类型 uint16_t
,这是不应该的。)
你可能会更成功地使用
ctypedef unsigned short *ushort_p "ushort_p"
出于某种原因,Cython 似乎不识别 C 语言中的 const
关键字。你可能需要在你的回调函数周围加一个包装器来处理 const
的问题。
如果你想把指针转换成 Python 对象,可以把它放在一个 cdef class
里。确保这个类记录了高度和宽度,因为这些信息在 C 数组中是没有记录的。