如何在Cython中声明列表的列表?附相关.pyx代码示例
在Cython中声明列表的列表的几种方法
嘿,我来结合你的代码片段,聊聊Cython里怎么处理嵌套列表(列表的列表)~你的现有写法是可行的,但我们可以根据性能需求选择不同的实现方式:
1. 你当前的Python风格写法(简单但性能一般)
你用的是Python原生的列表推导:
z = [[0]*(n+1) for _ in range(n*(2*n-1))]
这种写法在Cython里完全能运行,但本质上还是Python list对象的嵌套,每次访问元素都会有Python层面的类型检查和开销,适合快速开发但对性能要求不高的场景。
2. 添加类型注解的Python列表(小幅度提升性能)
如果想在保留Python列表灵活性的同时提升一点性能,可以用Cython 3.0+支持的泛型列表类型注解,明确指定嵌套列表的元素类型:
def f(m): cdef int n = len(m)//2 # 建议用//做整数除法,避免浮点数 cdef list[list[int]] z # 声明z是int类型的嵌套列表 z = [[0]*(n+1) for _ in range(n*(2*n-1))] # ... 后续代码不变
这样Cython会在编译时做类型优化,访问z[i][j]时的开销会比无注解的Python列表小一些。
3. C风格二维数组(性能最优,手动管理内存)
如果你的场景对性能要求极高,推荐用C层面的二维数组,完全绕开Python对象的开销。需要注意要手动分配和释放内存:
from libc.stdlib cimport malloc, free @cython.boundscheck(False) @cython.cdivision(True) @cython.wraparound(False) def f(m): cdef int n = len(m)//2 cdef int j, k cdef int rows = n*(2*n-1) cdef int cols = n+1 # 分配二维数组 cdef int **z = <int**>malloc(rows * sizeof(int*)) for j in range(rows): z[j] = <int*>malloc(cols * sizeof(int)) # 初始化子数组为0 for k in range(cols): z[j][k] = 0 # 你的业务逻辑 for j in range(1, 2*n): for k in range(j): z[j*(j-1)//2 + k][0] = m[j][k] # 调用solve前可以把C数组转成Python列表(如果solve需要Python列表的话) # 或者修改solve的参数为C数组类型 result = solve(z, 2*n, 1, [1] + [0]*n, n) # 释放内存!一定要记得,否则会泄漏 for j in range(rows): free(z[j]) free(z) return result
这种方式访问元素的速度和纯C一样快,但需要仔细管理内存,避免泄漏。
4. Cython内存视图(安全且高性能)
如果不想手动管理内存,又想接近C数组的性能,推荐用Cython内存视图,它是类型安全的,自动管理内存,还能和Python列表互相转换:
from cython.view cimport array as cvarray @cython.boundscheck(False) @cython.cdivision(True) @cython.wraparound(False) def f(m): cdef int n = len(m)//2 cdef int j, k cdef int rows = n*(2*n-1) cdef int cols = n+1 # 创建int类型的二维内存视图,初始化为0 cdef int[:, :] z = cvarray(shape=(rows, cols), itemsize=sizeof(int), format="i") z[:, :] = 0 # 批量初始化所有元素为0 # 访问方式和Python列表类似,但速度快很多 for j in range(1, 2*n): for k in range(j): z[j*(j-1)//2 + k][0] = m[j][k] # 如果solve需要Python列表,可以把内存视图转成列表: z_py = [list(row) for row in z] result = solve(z_py, 2*n, 1, [1] + [0]*n, n) return result
内存视图的访问性能接近C数组,而且不用手动释放内存,非常适合大多数性能敏感的场景。
针对你代码里的solve函数的小建议
你在solve里用了c = [b[(j+1)*(j+2)//2+k+2][:] for j in range(1, s-2) for k in range(j)],同样可以把b改成内存视图或者C数组,来提升循环内的访问速度。
内容的提问来源于stack exchange,提问作者Simd
相关产品推荐
相关产品推荐

