使用cython来提前输入类属性

8 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
Run Code Online (Sandbox Code Playgroud)

该错误涉及最后一行涉及的语法self.var1.我不允许直接输入类属性吗?我是否总是要将其分解为两个步骤,例如:

cdef double var1
self.var1 = var1
Run Code Online (Sandbox Code Playgroud)

完整的错误回溯是,

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
Run Code Online (Sandbox Code Playgroud)

Bak*_*riu 11

你想要的是定义一个扩展类型.特别是您的代码应如下所示:

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
Run Code Online (Sandbox Code Playgroud)

请注意,您不能在正常情况下强加实例属性的类型class,因为python允许人们更改它们及其类型.如果你试图cdef在普通的python类中放置一个类级别,你将收到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
Run Code Online (Sandbox Code Playgroud)

现在,这不是语法错误.语法很好.问题是你根本不能拥有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
Run Code Online (Sandbox Code Playgroud)

输出:

$cython test_cython.pyx 
$
Run Code Online (Sandbox Code Playgroud)

注意:没有输出cython意味着文件已成功编译.

我在上面链接的文档中解释了这个限制,参见属性:

扩展类型的属性直接存储在对象的C中 struct.[omissis]

注意:您只能为Python访问公开简单的C类型,例如整数,浮点数和字符串.您还可以公开Python值属性.

您只能公开简单 C数据类型的事实是因为属性是struct.允许像这样的缓冲区np.ndarray需要具有可变大小structs.

如果你想要一个类型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
Run Code Online (Sandbox Code Playgroud)

但是现在每次访问时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]
Run Code Online (Sandbox Code Playgroud)

通过这种方式,do_stuff你可以在函数内部使用cython的所有速度ar.

  • 值得注意的是,memoryview语法(`double [:]`)不需要在`object`和它的真实类型之间继续进行转换,所以应该更快. (4认同)