使用Cython,我试图将Python列表转换为Cython数组,反之亦然。 Python列表包含0到255范围内的数字,因此我将数组的类型指定为unsigned char
数组。以下是执行转换的代码:
from libc.stdlib cimport malloc
cdef to_array(list pylist):
cdef unsigned char *array
array = <unsigned char *>malloc(len(pylist) * sizeof(unsigned char))
cdef long count = 0
for item in pylist:
array[count] = item
count += 1
return array
cdef to_list(array):
pylist = [item for item in array]
return pylist
def donothing(pylist):
return to_list(to_array(pylist))
问题在于,在Cython数组中生成了多条垃圾数据,当转换为Python列表时,垃圾数据会继续存在。例如,donothing
应该什么都不做,并将python列表返回给我,保持不变。这个函数只是用于测试转换,但是当我运行它时,我会得到类似的东西:
In[56]: donothing([2,3,4,5])
Out[56]: [2, 3, 4, 5, 128, 28, 184, 6, 161, 148, 185, 69, 106, 101]
这些数据来自代码,这些垃圾如何清理,以免浪费内存?
P.S。从Python列表中获取数字并将它们注入unsigned char
数组可能有更好的版本。如果是这样,请完全指导我使用更好的方法。
答案 0 :(得分:3)
您的to_array
具有无类型的返回值。此外,您将结果分配给无类型值。因此,Cython被迫将char *
转换为Python类型。
Cython会转换为bytes
,因为char
约为bytes
。不幸的是,如果没有明确给定的长度,Cython会假定char *
以空值终止。这就是导致问题的原因:
convert_lists.donothing([1, 2, 3, 0, 4, 5, 6])
#>>> [1, 2, 3]
当没有零时,Cython将只读到它找到一个,超过实际分配的内存。
对于任意Cython类型,您实际上无法for x in my_pointer_arrray
。 for
循环实际上是在错误转换的bytes
上运行。
您可以通过键入所有值来修复此问题,这些值将保存char
数组,显式传递长度并循环范围(当输入循环变量时也会更快) ),或使用某种包装。有关使用哪个包装器数组的想法,this question and answer pair has you covered。
另请注意,使用手动分配时,您应该非常小心错误。 malloc
数据不是垃圾收集的,因此如果您错误地使用了代码路径,那么您将会泄漏内存。您应该检查如何处理每个特定情况。