如何在Cython中声明2D列表

时间:2013-01-02 09:01:16

标签: python cython

我正在尝试编译这种代码:

def my_func(double c, int m):
    cdef double f[m][m]

    f = [[c for x in range(m)] for y in range(m)]
    ...

提出:

Error compiling Cython file:
------------------------------------------------------------
def grow(double alpha, double beta, double gamma, int m, int s):
    cdef double f[m][m]
                     ^
------------------------------------------------------------
test.pyx:6:22: Not allowed in a constant expression

之后我假设我不能在指向的位置使用变量,我尝试使用数值:

def my_func(double c, int m):
    cdef double f[500][500]

    f = [[c for x in range(500)] for y in range(500)]
    ...

然后我得到:

Error compiling Cython file:
------------------------------------------------------------
    f = [[beta for x in range(500)] for y in range(500)]
     ^
------------------------------------------------------------
test.pyx:13:6: Assignment to non-lvalue 'f'

所以,我想知道如何在cython代码中声明和制作2D列表。我在google搜索“cython 2D list”的文档中找不到这种例子

2 个答案:

答案 0 :(得分:8)

不要在Cython中使用列表推导。他们创建常规的python列表没有加速。 Wiki says,您应该在Cython中使用动态分配,如下所示:

from libc.stdlib cimport malloc, free

def my_func(double c, int m):
    cdef int x
    cdef int y
    cdef double *my_array = <double *>malloc(m * m * sizeof(double))

    try:

        for y in range(m):
            for x in range(m):
                #Row major array access
                my_array[ x + y * m ] = c

        #do some thing with my_array

    finally:
       free( my_array )

但是如果你需要一个2D数组的python对象,建议使用NumPy

答案 1 :(得分:7)

cdef double f[500][500]

这是宣布500个双打500 C阵列的C阵列。这是500 * 500打包的双值(在这种情况下存储在堆栈中,除非Cython做了一些时髦的事情)没有任何间接,这有助于提高性能和缓存利用率,但显然会增加严格的限制。也许你想要这个,但你应该学习足够的C来了解这意味着什么。顺便说一句,一个限制是大小必须是编译时常量(取决于C版本; C99和C10允许它),这是第一个错误消息的内容。

如果您使用数组,则不会按照您的方式初始化f,因为这没有任何意义。 f已经是500x500双变量,并且无法将数组作为一个整体分配(后者的错误消息试图告诉您)。特别是,list comprehension创建了一个完整的Python列表对象(您也可以使用Cython,见下文),其中包含完全成熟的“盒装”Python对象(在本例中为float个对象)。列表与C数组不兼容。使用带有项目分配的嵌套for循环进行初始化。最后,这样的数组需要500 * 500 * 8字节,几乎是2 MiB。在某些系统上,这比整个堆栈大,而在所有其他系统上,它是堆栈的如此大部分,这是一个坏主意。你应该堆分配该数组。

如果您使用Python列表,请注意您在性能和内存使用方面不会得到很大改进(假设您的代码主要是操作该列表),尽管您可能会获得一些回报。你可以放弃cdef,或者使用list作为类型(object也可以使用,但你从中获得任何东西,所以你也可以省略它。)

NumPy阵列可能更快,内存效率更高,使用起来更方便。如果您可以根据NumPy的操作实现算法的性能关键部分,则可以在不使用Cython 的情况下获得所需的加速