我想以cython格式重写一个类,并将其保存为demo.pyx。该类的输入参数可以是2D np。具有Nx2
形状的数组,例如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
我知道我使用指针的方式有问题,但是如果我想保持x
和y
的类型不明确,我需要使用它。我怎样才能使我的class
工作?
当您执行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]
注意:
YES,您可以将数组中元素的地址用作
double *
数组,例如对于b=&positions[0,0]
;positions[0,0]==b[0]
和positions[0,0+1]==b[1]
;当positions
是c连续的2D数组时。您没有将np.ndarray
转换为double *
,只是直接从内存访问其数据;我使用
.copy()
来保证内存中有连续的数据。 如果
positions
是fortrans -连续的,则不需要这样做。&
操作符接受对象的地址。将self.x
指定为positions[0]
的地址。所以应该是self.x = &position[0]
。这读起来就像将self的成员x设置为position的第0个元素的地址。你要做的就是把x的地址设为。但你不能这么做。&
只允许出现在等式的右边
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.
也许你应该在halo_positions
类中保留对positions
的引用。
您的代码有几个问题。首先,也是最容易修复的,是没有"unsigned double"这样的东西,所以你应该删除unsigned
作为开始。
同样,&positions[:,0]
不是获取数组地址的正确语法,因为:
将返回一个Python对象。您需要执行&positions[0,0]
,它指向数组的初始元素。
应该指出的是,你的__init__
只适用于Numpy数组,而不是列表,正如你所说的那样。您必须事先将任何列表转换为数组。还要记住,你需要通过指针对你使用的任何数组保持一个活动引用,否则你会遇到麻烦。
根据你想对代码做什么,在类中使用指针变量可能不是最安全的选择。
我从cython得到的答案。Group in Google works perfect:
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