在cython中使用numpy.array

时间:2014-06-09 05:13:47

标签: python arrays pointers numpy cython

我想以 cython 格式重写一个类并将其另存为demo.pyx。该类的输入参数可以是具有Nx2形状的 2D np.array ,例如a=np.array([[0.2,-0.8],[3.7,0.02],..,[-0.92,-3.33]])instance a=[0.1,2.7]的列表。

cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef unsigned double *x 
    cdef unsigned double *y 
    def __init__(self, np.ndarray[np.float64_t,ndim=2,mode='c'] positions):
        self.x = &positions[:,0]
        self.y = &positions[:,1]

我试图编写的内容会导致错误消息如下:

running build_ext
cythoning demo.pyx to demo.c

Error compiling Cython file:
------------------------------------------------------------
...
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef unsigned double *x 
        ^
------------------------------------------------------------

demo.pyx:5:9: Unrecognised type modifier combination

Error compiling Cython file:
------------------------------------------------------------
...
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef unsigned double *x 
    cdef unsigned double *y 
        ^
------------------------------------------------------------

demo.pyx:6:9: Unrecognised type modifier combination

Error compiling Cython file:
------------------------------------------------------------
...
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef unsigned double *x 
    cdef unsigned double *y 
    def __init__(self, np.ndarray[np.float64_t,ndim=2,mode='c'] positions):
        self.x = &positions[:,0]
                ^
------------------------------------------------------------

demo.pyx:8:17: Cannot take address of Python variable

Error compiling Cython file:
------------------------------------------------------------
...
cdef class halo_positions(object):
    cdef unsigned double *x 
    cdef unsigned double *y 
    def __init__(self, np.ndarray[np.float64_t,ndim=2,mode='c'] positions):
        self.x = &positions[:,0]
        self.y = &positions[:,1]
                ^
------------------------------------------------------------

demo.pyx:9:17: Cannot take address of Python variable

我知道我使用指针的方式存在问题,但如果我想保持xy的类型不明确,我需要使用它。我怎样才能使class工作?

5 个答案:

答案 0 :(得分:2)

当您执行positions[:,0]positions[:,1]时,您将在Cython中创建一个新的1D和未声明的缓冲区。这不是您可以从中获取地址的元素。地址将对应于数组中的单个值,因此您应该执行以下操作:

cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
    cdef double *x 
    cdef double *y 
    def __init__(self, np.ndarray[np.float64_t, ndim=2, mode='c'] positions):
        cdef np.ndarray[np.float64_t, ndim=1] buffx, buffy
        buffx = positions[:,0].copy()
        buffy = positions[:,1].copy()
        self.x = &buffx[0]
        self.y = &buffy[0]

请注意:

  • ,您可以获取数组中元素的地址,并将其用作double *数组,以便b=&positions[0,0]; positions[0,0]==b[0]positions[0,0+1]==b[1];当positions是C连续的2D数组时。您没有将np.ndarray转换为double *,只是直接从内存中访问其数据;

  • 我正在使用.copy()来保证您在内存中有连续的数据。如果positions是Fortran连续的,那就没必要了。

答案 1 :(得分:0)

&运算符获取对象的地址。您希望将self.x指定为positions[0]的地址。所以它应该是self.x = &position[0]。这将设置为self的成员,称为x的第0个元素的地址。你试图做的是将x的地址设置为某种东西。但你不能这样做。 &仅允许在方程式的右侧。

答案 2 :(得分:0)

Cython无法将numpy数组转换为double *,您可以改为使用double[:],例如:

cimport numpy as np
cdef class halo_positions(object):
    cdef double *x 
    cdef double *y 
    def __init__(self, double[:] positions):
        self.x = &positions[0]
        self.y = &positions[1]

    def debug(self):
        print self.x[0], self.y[0]

但这非常危险:

a = np.array([1.0, 2.0, 3.0, 4.0])
hp = halo_positions(a)
hp.debug()
del a
hp.debug() # x and y is wild pointer now.

也许您应该在positions课程中保留对halo_positions的引用。

答案 3 :(得分:0)

您的代码存在一些问题。首先,最容易修复的是,没有“unsigned double”这样的东西,所以你应该删除unsigned开头。

此外,&positions[:,0]不是获取数组地址的正确语法,因为:将返回Python对象。你需要做&positions[0,0],它指向数组的初始元素。

应该指出的是,__init__仅适用于Numpy数组,而不适用于您所声明的列表。您必须事先将任何列表转换为数组。另外请记住,你需要通过指针保持对你使用的任何数组的有效引用,否则你将遇到麻烦。

根据您对代码的处理方式,在类中使用指针变量可能不是最安全的选择。

答案 4 :(得分:0)

我从谷歌的cython.group得到的答案完美无缺:

import cython
cimport cython

import numpy as np
cimport numpy as np

DTYPE = np.float64
ctypedef np.float64_t DTYPE_t

cdef class halo_positions(object):

    cdef double [:] _x
    property x:
        def __get__(self):
            return np.array(self._x)
        def __set__(self, np.ndarray[DTYPE_t, ndim=1] x):
            self._x = x

    cdef double [:] _y
    property y:
        def __get__(self):
            return np.array(self._y)
        def __set__(self, np.ndarray[DTYPE_t, ndim=1] y):
            self._y = y

    def __init__(self, np.ndarray[DTYPE_t,ndim=2] positions):
        self._x = positions[:,0]
        self._y = positions[:,1]

    def debug(self):
        print self.x, self.y