如何在Cython中创建变长数组指针数组并传递给Python?
在Cython中创建指向不同长度数组的指针数组并返回给Python的解决方案
完全可行,但你的代码里用cpython array模块存储指针的方式存在问题,这就是编译报错Buffers with pointer types not yet supported的核心原因——Python的array模块仅支持存储基本数值类型(如int、float),无法存储指针类型。
原代码的关键错误
- 错误1:
arr.array[unsigned int *]这种定义不被支持,array模块没有存储指针的能力。 - 错误2:获取数组指针的方式错误,
Message1[0]是数组的第一个元素值,而非底层指针,正确的方式是使用Message1.data获取数组的C语言底层指针。
方案1:直接返回Python列表(最简单,推荐)
不需要手动维护C指针数组,直接将各个array对象放入Python列表返回,Python端可直接通过索引访问子数组,完全满足需求。
修改后的代码:
# cython: language_level=3 from cpython cimport array as arr def mainFunc(): array_list = ArrayOfPointersGenerator("path") print(array_list[0][1]) # 输出12 print(array_list[1][2]) # 输出23 return 0 def ArrayOfPointersGenerator(path): cdef arr.array[unsigned int] Message1, Message2 Message1 = arr.clone(arr.array('I'), 2, False) Message1[0] = 11 Message1[1] = 12 Message2 = arr.clone(arr.array('I'), 3, False) Message2[0] = 21 Message2[1] = 22 Message2[2] = 23 # 直接返回包含子数组的Python列表 return [Message1, Message2]
该方案无需处理内存管理,Python端可像操作普通列表和数组一样使用,简洁高效。
方案2:自定义Cython类封装C指针数组(适用于性能敏感场景)
如果确实需要在C层面维护指针数组,可封装成自定义Cython类,手动管理内存避免泄漏,同时保证Python端可正常访问。
代码示例:
# cython: language_level=3 from cpython cimport array as arr from libc.stdlib cimport malloc, free cdef class PointerArray: cdef unsigned int** ptr_array cdef int length cdef list arrays # 保存原始array对象,防止被Python GC回收导致指针悬空 def __cinit__(self, int length): self.length = length # 分配C指针数组的内存 self.ptr_array = <unsigned int**>malloc(length * sizeof(unsigned int*)) self.arrays = [] def __dealloc__(self): # 对象销毁时释放C层面的内存 if self.ptr_array is not NULL: free(self.ptr_array) def add_array(self, arr.array[unsigned int] arr_obj): # 保存原始数组,避免GC回收 self.arrays.append(arr_obj) # 记录数组的底层指针 self.ptr_array[len(self.arrays)-1] = arr_obj.data def __getitem__(self, int idx): if idx < 0 or idx >= self.length: raise IndexError("索引超出范围") # 返回原始数组对象,方便Python访问 return self.arrays[idx] def mainFunc(): pa = ArrayOfPointersGenerator("path") print(pa[0][1]) # 输出12 print(pa[1][2]) # 输出23 return 0 def ArrayOfPointersGenerator(path): cdef arr.array[unsigned int] Message1, Message2 cdef PointerArray pa = PointerArray(2) Message1 = arr.clone(arr.array('I'), 2, False) Message1[0] = 11 Message1[1] = 12 Message2 = arr.clone(arr.array('I'), 3, False) Message2[0] = 21 Message2[1] = 22 Message2[2] = 23 pa.add_array(Message1) pa.add_array(Message2) return pa
这里通过arrays列表保存原始数组对象,防止Python垃圾回收器销毁它们导致C指针失效;__dealloc__方法负责在自定义类对象被销毁时释放C层面分配的内存。
内容的提问来源于stack exchange,提问作者Ivaylo
相关产品推荐
相关产品推荐

