我正在尝试使用 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]
这些数据在代码中来自哪里,如何清理这些垃圾才不会浪费内存?
附言从 Python 列表中获取数字并将它们注入(inject) unsigned char
数组可能有更好的版本。如果是这样,请指导我完全采用更好的方法。
最佳答案
您的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
数组的 all 值来解决此问题,显式传递长度并在范围内循环(循环时也会更快)变量是类型化的),或者通过使用某种包装器。有关使用什么包装器数组的想法,this question and answer pair has you covered .
另请注意,在使用手动分配时,您应该非常小心错误。 malloc
的数据不会被垃圾收集,因此如果您在代码路径之外出错,您将泄漏内存。您应该检查如何处理每个特定案例。
关于python - Python 列表中的额外元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24102447/