我想以 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
我知道我使用指针的方式存在问题,但如果我想保持x
和y
的类型不明确,我需要使用它。我怎样才能使class
工作?
答案 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