2014-01-15 32 views
5

私はPythonクラスを作成しています。早期にタイプを入力することで実行を高速化したいと思います。
私は次のようにコンパイルcythonしようとすると、エラー"Syntax error in C variable declaration"を得る:cythonを使用してクラス属性を早期に入力する

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 

完全なエラートレースバックがある、のような2つのステップにこれを破るために

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

トレースバックを追加 –

+0

これは完全なトレースバックではありません。 – Bakuriu

答えて

10

を持っていますと、extension typeを定義することです。 Pythonは、人々が彼らと彼らの種類を変更することができますので、あなたが、通常class内のインスタンスの種類属性を課さないでき

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 

注:特に、あなたのコードは次のようになります。通常の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から出力なし。

この制限は、セクションAttributesで、私は上記のリンク先のドキュメントで説明されています。

Attributes of an extension type are stored directly in the object’s C struct. [omissis]

Note: You can only expose simple C types, such as ints, floats, and strings, for Python access. You can also expose Python-valued attributes.

属性がstructのメンバーであるので、あなただけシンプル Cデータ・タイプを公開することができるという事実であります。 np.ndarrayのようなバッファを許可するには、可変サイズstructが必要です。

あなたがタイプ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] 

あなたがarを使用してcythonのすべての速度を持つことができdo_stuff関数内。

+0

その解決策は別のエラーメッセージを生成し、私はそれを投稿に追加しました。 –

+4

memoryviewの構文( 'double [:]')は、 'object'とその実際の型の間でキャストを続ける必要がないので、はるかに速くなければなりません。 – Veedrac

+0

これは混乱する答えです。可変長の配列とは関係ありません。私は自分自身のcppクラス(スタック上に作成されていますがバッファではありません)を持つことができますが、これは理由ではありません: – dashesy

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) 
関連する問題