使用cython来提前输入类属性

时间:2014-01-15 07:56:29

标签: python class cython

我正在写一个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

2 个答案:

答案 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)