pure Python モード

Cyhton の言語コンストラクトを使うと、同じファイルをインタプリタで実行 したり、コンパイルして実行したりできます。これは、 Cython が同じ名前の 「魔法の」 cython モジュールを用意していて、そこに入っているディレ クティブを import して使うようになっているからです。 cython は、 .py 形式と .pyx 形式の両方で提供されています。

pure Python モードを使うには、特別な関数やデコレータを利用します。また、 (必要に応じて) 補助 .pxd ファイル (augmenting .pxd) を 使います。

マジック・アトリビュート

cython モジュールは、現在今のようなアトリビュートをサポートしてい ます:

  • declare は、現在のスコープ内で変数の型宣言を行います。これは cdef type var [= value] コンストラクトの代わりになります。 declare には二つの形式があり、一つは代入型です (この形式は、イン タプリタモードでも宣言を作れる点が便利です):

    x = cython.declare(cython.int)             # cdef int x
    y = cython.declare(cython.double, 0.57721) # cdef double y = 0.57721
    

    もう一つはより単純な関数呼び出し型です。:

    cython.declare(x=cython.int, y=cython.double) # cdef int x; cdef double y
    
  • locals は、関数本体内のローカル変数 (引数型の一部、または全部を 含む) の型定義に使うデコレータです:

    @cython.locals(a=cython.double, b=cython.double, n=cython.p_double)
    def foo(a, b, x, y):
        ...
    
  • address& 演算子の代わりに使います:

    cython.declare(x=cython.int, x_ptr=cython.p_int)
    x_ptr = cython.address(x)
    
  • sizeofsizeof 演算子をエミュレートします。型に対しても、式 に対しても使えます:

    cython.declare(n=cython.longlong)
    print cython.sizeof(cython.longlong), cython.sizeof(n)
    
  • struct は構造体型を作るのに使えます。以下のコード:

    MyStruct = cython.struct(x=cython.int, y=cython.int, data=cython.double)
    a = cython.declare(MyStruct)
    

    は、Cython の下記のコードと等価です:

    cdef struct MyStruct:
        int x
        int y
        double data
    
    cdef MyStruct a
    
  • union は共用体型を作ります。構文は struct と同じです。

  • typedef は新たな型を定義します:

    T = cython.typedef(cython.p_int)   # ctypedef int* T
    
  • compiled は特別な変数で、コンパイルして実行するときは True, インタプリタで実行するときは False にセットされます。従って、以 下のようなコード:

    if cython.compiled:
        print "Yep, I'm compiled."
    else:
        print "Just a lowly interpreted script."
    

    は、コードがコンパイルされた .so と素の .py ファイル のどちらからロードされたかで異なる振る舞いをします。

補助 (agumenting) .pxd ファイル

.py ファイルと同名の .pxd が見つかると、 Cython は cdef されたクラスや、 cdef/cpdef され た関数やメソッドを走査します。次に、 .py 中の対応するクラス・ 関数・メソッドを、適切な型に変換します。 従って、もし下記のような a.pxd があったとして、:

cdef class A:
    cpdef foo(self, int i)

同時に以下のような a.py というファイルがあると、:

class A:
    def foo(self, i):
        print "Big" if i > 1000 else "Small"

コードは下記のように解釈されます:

cdef class A:
    cpdef foo(self, int i):
        print "Big" if i > 1000 else "Small"

cython モジュールは、補助 .pxd ファイル (augmenting .pxd) の中でも import できます。それによって、 pure Python ファ イル側に手を入れなくても、 purePython ファイルに型付け情報を追加できま す。例えば、以下のような pythonファイル dostuff.py があったとします。:

def dostuff(n):
    t = 0
    for i in range(n):
        t += i
    return t

このファイルは、以下のような .pxd ファイル dostuff.pxd で「補助」できます:

import cython

@cython.locals(t = cython.int, i = cython.int)
cpdef int dostuff(int n)

cython.locals デコレータの他にも、 cython.declare() 関数を使っ て、補助ファイル中のグローバル変数に型宣言をおこなったりできます。

.pxd ファイル中では通常の Python の関数宣言 (def) はできないので、例えば *args**kwargs といったシグネチャを 持つ関数の型を .pxd でオーバライドすることは、現状できません。 注意してください。

データ型

cython モジュールには様々なデータ型が定義されています。まず、標準 C の データ型である char, short, int, long, longlong, 符号なし型である uchar, ushort, uint, ulong, ulonglong, また、 bintPy_ssize_t も定義しています。 どの型に対しても、 p_int, pp_int, . . ., といったような形で、 インタプリタモードでは 3 段階の深さ、コンパイルモードでは任意の深さま でのポインタ型があります。 Python の int, long, bool 型は、 C ではそれぞれ int, long, bint に変換されます。また、Python の list, dict, tuple, . . . といった型や、ユーザ定義の型も使えます。

ポインタ型は cython.pointer(cython.int) のようにして、配列型は cython.int[10] のようにして宣言できます。こうした比較的複雑なデー タ型のエミュレーションは部分的にサポートしていますが、せいぜい Python で程度のエミュレーションです。

拡張型と cdef 関数

cdef class の作成には @cython.cclass デコレータを使います。 cdef 関数には @cython.cfunc デコレータを、 cpdef 関数には @cython.ccall デコレータをそれぞれ使いま す。引数の型を宣言するには、 @cython.locals() デコレータを使います。 戻り値の型を宣言するには、 @cython.returns(a_type) を使います。

cdef 関数の例を以下に示します:

@cython.cfunc
@cython.returns(cython.bint)
@cython.locals(a=cython.int, b=cython.int)
def c_compare(a,b):
    return a == b

Table Of Contents

Previous topic

unicode と文字列の扱い

Next topic

NumPy を扱う

This Page