使用cython早期输入类属性 [英] Using cython to early type class attributes
问题描述
我正在编写一个python类,我想使用cython早期输入来加快执行速度。
我收到了错误 C变量声明中的语法错误 当我尝试cython编译以下内容时:
I'm writing a python class and I would like to accelerate the execution using cython early typing.
I get the error "Syntax error in C variable declaration"
when I try to cython compile the following:
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 <的最后一行的语法/ code>。我不允许直接键入类属性吗?我是否总是必须将其分为两个步骤,例如,
The error concerns the syntax of the last line involving self.var1
. Am I not allowed to type class attributes directly? Do I always have to break this up into two steps such as,
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
推荐答案
您要定义的是 extension 类型。特别是您的代码应如下所示:
What you want is to define an extension type. In particular your code should look like:
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允许人们更改它们及其类型。如果您尝试将 cdef
放在普通python类的类级别,则会收到Cython的编译器错误。
Note that you cannot impose the type of instance attributes in a normal class
, because python allow people to change them and their types. If you try to put a cdef
at class level in a normal python class you'll receive a compiler error by Cython.
编译上面的代码会引发以下错误:
Compiling the above code raises the following error:
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
行,则文件将正确编译:
Now, this is not a syntax error. The syntax is fine. The problem is that you simply cannot have an instance attribute with np.ndarray
as type. It is a limitation of cython. In fact if you comment the cdef np.ndarray[double, ndim=1] Redges
line the file is compiled correctly:
代码:
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
没有输出,表示文件已成功编译。
Note: no output from cython
which means the file was compiled succesfully.
此限制在上面链接的文档中,属性:
this limitation is explained in the documentation I linked above, at the section Attributes:
扩展类型的属性直接存储在对象的C
struct
中/ em>。 [omissis]
Attributes of an extension type are stored directly in the object’s C
struct
. [omissis]
注意:您只能公开简单的C类型,例如int,float和字符串,用于Python访问。您还可以公开Python值的
属性。
Note: You can only expose simple C types, such as ints, floats, and strings, for Python access. You can also expose Python-valued attributes.
您只能公开简单 C数据类型是因为属性是 struct
的成员。允许像 np.ndarray
这样的缓冲区需要具有可变大小 struct
s。
The fact that you can only expose simple C data-types is because the attributes are members of the struct
. Allowing a buffer like an np.ndarray
would require to have variable size struct
s.
如果想要类型为 np.ndarray
的实例属性,则最好的办法是定义一个通用类型为<$ c的属性。 $ c>对象并为其分配数组:
If you want an instance attribute of type np.ndarray
the best you can do is to define an attribute with a generic type of object
and assign the array to it:
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
但是现在每次访问< codeself.Redges 您会失去cython的速度。如果您多次访问它,则可以将其分配给具有正确类型的局部变量。
这是我的意思:
However now everytime you access self.Redges
you lose the speed up of cython. If you access it many times you can assign it to a local variable with the correct type.
Here's what I mean:
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]
code> do_stuff 函数,您可以使用 ar
获得cython的所有速度。
In this way inside the do_stuff
function you can have all the speed of cython using ar
.
这篇关于使用cython早期输入类属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!