Cython对象成员的缓冲区声明

22 投票
2 回答
3528 浏览
提问于 2025-04-17 09:56

我想创建一个Cython的“cdef”对象,里面有一个NumPy成员,并且能够快速访问这个成员的数据。理想情况下,我想做的事情是这样的:

import numpy as np
cimport numpy as np

cdef class Model:
  cdef np.ndarray[np.int_t, ndim=1] A

  def sum(self):
    cdef int i, s=0, N=len(self.A)
    for 0 <= i < N:
      s += self.A[i]
    return s

  def __init__(self):
    self.A = np.arange(1000)

可惜的是,Cython无法编译这个代码,会报错说 只允许将缓冲区类型作为函数局部变量

我现在的解决办法是,在一个新的局部变量中声明缓冲区属性,并把它赋值给对象的成员:

cdef class Model:
  cdef np.ndarray A

  def sum(self):
    cdef int i, s=0, N=len(self.A)
    cdef np.ndarray[np.int_t, ndim=1] A = self.A
    for 0 <= i < N:
      s += A[i]
    return s

如果你想让多个方法访问同样的数据结构,这就变得非常麻烦了——这似乎是一个相当常见的使用场景,对吧?

有没有更好的解决方案,不需要在每个方法里重新声明类型呢?

2 个回答

6

你现在用的解决方案就是我通常会用的,也就是在函数里做一个本地的副本。这种做法虽然不算优雅,但我觉得对性能影响不大(至少在我的情况下,我在这个方法里做了很多工作,所以没什么明显的差别)。我还在 __cinit__ 方法里创建了一个 C 数组,然后在 __init__ 中填充数据(记得用 __dealloc__ 来正确清理)。这样做会失去一些 numpy 数组的功能,但你仍然可以像使用 C 数组那样使用它。

你也可以看看这个旧邮件中关于 cython 的讨论:

http://codespeak.net/pipermail/cython-dev/2009-April/005214.html

14

你可以选择使用内存切片或者Cython数组来进行工作。想了解更多,可以查看这个链接:http://docs.cython.org/src/userguide/memoryviews.html

import numpy as np
cimport numpy as np

  cdef class Model:

    cdef int [:] A

    def sum(self):

        for 0 <= i < N:
            s += self.A[i]
        return s

    def __init__(self):
        self.A = np.arange(1000)

撰写回答