Python列表中的额外元素

时间:2014-06-08 01:09:04

标签: python cython

使用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数组可能有更好的版本。如果是这样,请完全指导我使用更好的方法。

1 个答案:

答案 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_arrrayfor循环实际上是在错误转换的bytes上运行。

您可以通过键入所有值来修复此问题,这些值将保存char数组,显式传递长度并循环范围(当输入循环变量时也会更快) ),或使用某种包装。有关使用哪个包装器数组的想法,this question and answer pair has you covered


另请注意,使用手动分配时,您应该非常小心错误。 malloc数据不是垃圾收集的,因此如果您错误地使用了代码路径,那么您将会泄漏内存。您应该检查如何处理每个特定情况。