我正在写一个python类,我想用cython早期打字来加速执行
当我尝试cython编译以下内容时,我收到错误"Syntax error in C variable declaration"
:
import numpy as np
cimport numpy as np
class MyClass:
def __init__( self, np.ndarray[double, ndim=1] Redges ):
self.Redges = Redges
cdef double self.var1
该错误涉及涉及self.var1
的最后一行的语法。我不允许直接输入类属性吗?我是否总是要将其分解为两个步骤,例如
cdef double var1
self.var1 = var1
完整的错误追溯是,
test.pyx:7:24:
Syntax error in C variable declaration
Traceback (most recent call last):
File "setup.py", line 9, in <module>
ext_modules = cythonize('test.pyx'), # accepts a glob pattern
File "/usr/lib/python2.7/dist-packages/Cython/Build/Dependencies.py", line 713, in cythonize
cythonize_one(*args[1:])
File "/usr/lib/python2.7/dist-packages/Cython/Build/Dependencies.py", line 780, in cythonize_one
raise CompileError(None, pyx_file)
Cython.Compiler.Errors.CompileError: calc_iliev_sphere.pyx
答案 0 :(得分:11)
您想要的是定义extension type。特别是您的代码应如下所示:
import numpy as np
cimport numpy as np
cdef class MyClass:
cdef double var1
cdef np.ndarray[double, ndim=1] Redges
def __init__( self, np.ndarray[double, ndim=1] Redges ):
self.Redges = Redges
请注意,无法将实例属性的类型强加到普通class
中,因为python允许人们更改它们及其类型。如果你试图在普通python类的类级别放置cdef
,你将收到Cython的编译器错误。
编译上面的代码会引发以下错误:
Error compiling Cython file:
------------------------------------------------------------
...
import numpy as np
cimport numpy as np
cdef class MyClass:
cdef double var1
cdef np.ndarray[double, ndim=1] Redges
^
------------------------------------------------------------
test_cython.pyx:6:36: Buffer types only allowed as function local variables
现在,这是不语法错误。语法很好。问题是,您只是不能具有np.ndarray
类型的实例属性。这是cython的一个限制。实际上,如果您对cdef np.ndarray[double, ndim=1] Redges
行进行注释,则文件编译正确:
代码:
import numpy as np
cimport numpy as np
cdef class MyClass:
cdef double var1
#cdef np.ndarray[double, ndim=1] Redges
def __init__( self, np.ndarray[double, ndim=1] Redges ):
self.Redges = Redges
输出:
$cython test_cython.pyx
$
注意:cython
没有输出,这意味着文件已成功编译。
我在上面链接的文档[{3}}:
中解释了此限制扩展类型的属性直接存储在对象的C中
struct
的。 [omissis]注意:您只能为Python访问公开简单的C类型,例如整数,浮点数和字符串。您还可以公开Python值 属性。
您只能公开简单 C数据类型的事实是因为属性是struct
的成员。允许像np.ndarray
这样的缓冲区需要具有可变大小struct
s。
如果你想要一个np.ndarray
类型的实例属性,你可以做的最好的事情就是定义一个通用类型为object
的属性并将数组分配给它:
import numpy as np
cimport numpy as np
cdef class MyClass:
cdef double var1
cdef object Redges
def __init__( self, np.ndarray[double, ndim=1] Redges ):
self.Redges = Redges
但是现在每次访问self.Redges
时都会失去cython的速度。如果多次访问它,可以将其分配给具有正确类型的局部变量。
这就是我的意思:
import numpy as np
cimport numpy as np
cdef class MyClass:
cdef double var1
cdef object Redges
def __init__( self, np.ndarray[double, ndim=1] Redges ):
self.Redges = Redges
def do_stuff(self):
cdef np.ndarray[double, ndim=1] ar
ar = self.Redges
ar[0] += 1
return ar[0]
以这种方式在do_stuff
函数内部,您可以使用ar
获得所有cython的速度。
答案 1 :(得分:2)
@bakuriu的答案非常好,我想补充一下如何将内存视图保持为类成员:
import numpy as np
cimport numpy as np
cdef class MyClass:
cdef public double var1
cdef public np.float64_t[:] Redges
def __init__( self, np.ndarray[double, ndim=1] Redges ):
self.Redges = Redges
使用这种方法do_stuff
变得更简单:
def do_stuff(self):
# With using buffer protocol, this just wraps the memory view
# with numpy object without copying data
np_redges = np.asarray(self.Redges)
# Now you have np_redges, a numpy object. Even though, it's not a pure
# C array, it allows calling numpy functions with all the power of MKL, e.g.:
np.add(np_redges, 1.0, np_redges)