コンパイル

Python のコードと違い、Cython のコードを使うには、コンパイルする必要が あります。コンパイルには、二つのステージがあります:

  • まず、 .pyx ファイルを Cython で .c ファイルに変換します。
  • 上の .c ファイルを C コンパイラで .so ファイル (Windows の 場合には .pyd ファイル) にコンパイルします。

以下の節では、拡張モジュールをビルドする方法を複数通りにわたって解説し ています。また、 Cython コンパイラにディレクティブを渡す方法についても 説明します。

コマンドラインからコンパイルする

コマンドラインでコンパイルするには、 コマンドラインオプションと コンパイルしたい .pyx のリストを並べて Cython コンパイラを起動しま す:

$ cython -a yourmod.pyx

上のコマンドは yourmod.c ファイルを生成します。 -a スイッチをつけると、 html ファイルを生成します。 -h フラグを使うと、 cython コマンドのサポートする全フラグのリ ストを出力します。

.c ファイルのコンパイル方法は、使っているオペレーティングシステム によって異なります。システムごとの詳しい情報は、拡張モジュールの書き方 に関する Python のドキュメントにあるはずです。ここでは、 Linux システ ムの例を示しましょう:

$ gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing \
      -I/usr/include/python2.5 -o yourmod.so yourmod.c

[gcc には、 include したいヘッダファイルのパスと、リンクしたいライ ブラリへのパスを教えてやる必要があります]

コマンドを実行すると、 yourmod モジュールと同じディレクトリに yourmod.so ファイルができ、通常のモジュールと同様に import できま す。

distutils でコンパイルする

まず、 distutils がシステムに入っているか確認してください。通常は、 標準ライブラリの一部として入っているはずです。以下の例では、コンパイル 対象の Cython ファイルの名前を hello.pyx とします。 setup.py ス クリプトは下記のようになります:

from distutils.core import setup
from Cython.Build import cythonize

setup(
    name = "My hello app",
    ext_modules = cythonize('hello.pyx'), # accepts a glob pattern
)

コマンドラインシェルから python setup.py build_ext --inplace を実 行すれば、コンパイルは完了です。作成した拡張モジュールを、 python シェ ルやスクリプトで import してみましょう。

cythonize コマンドも使うと、マルチスレッドでコンパイルしたり依存関 係を解決したりできます。ターゲットファイルが、ソースファイルや依存関係 にあるファイルよりも新しければ、再コンパイルをスキップします。

pyximport でコンパイルする

pure Python モジュールの中で Cython コードを生成したければ、以下のよう にタイプします:

>>> import pyximport; pyximport.install()
>>> import helloworld
Hello World

このコマンドを使うと、Python がモジュールを import するたびに、Cython が自動的に対象の .pyx をコンパイルします。 この方法は、外部の C ライブラリや、ビルドに特殊なセットアップが必要な い、単純な Cython コードのビルドでのみ使いましょう。

Cython が Python モジュールのコンパイルに失敗すると、 pyximport は フォールバックとしてソースモジュールをロードしようとします。

pyximport は、 (標準ライブラリやシステムにインストールされているパッ ケージも含む)、 .py モジュールのコンパイルにも使えます。この機能を つかうには、 pyximport に以下のように引数を指定します:

>>> pyximport.install(pyimport = True)

cython.inline でコンパイルする

Cython のコードは、 SciPy の weave.inline と同じやりかたでコンパイ ルできます。例えば:

>>> import cython
>>> def f(a):
...     ret = cython.inline("return a+b", b=3)
...

cython.inline は、明示的に結びつけられていない変数を、コードの外側 のローカル変数やグローバル変数のスコープから取得します。コンパイルの結 果は、効率的に再利用できるよう、キャッシュされます。

Sage でのコンパイル

Sage のノートブックには、 Cython コードを透過的に編集・コンパイルする 機能があります。この機能を呼び出すには、セルの先頭で %cython とタ イプして、Cython コードを評価します。 Cython セル中で定義した変数や関 数は、実行中のセッションにそのまま import されます。 詳しくは Sage のドキュメント を参照 してください。

Cython コンパイラの挙動は、以下のディレクティブを指定することで調整で きます。

コンパイラディレクティブ

コンパイラディレクティブとは、Cython のコードの挙動に影響を及ぼす命令 です。現在サポートしているディレクティブは、以下の通りです:

boundscheck (True / False)
False にセットすると、 Cython はコード中のインデクス操作 ([]演算) が、一切 IndexError を送出しないものとみなします。 リスト、タプル、文字列は、インデクスが負でないとはっきりしていると き (あるいは、 wraparound が False にセットされているとき) の み、このディレクティブの影響を請けます。このディレクティブの値を False にセットすると、通常なら IndexError を起こすような操作を行っ た場合、注意してコードを書かなければ、 segfault を起こしたり、デー タを破損したりする可能性があります。
wraparound (True / False)
Python のアレイに対して、末尾からの相対値でのインデクスを可能にし ます。例えば、 A[-1] は、リストの末尾の値に対するインデクスです。 C は、負のインデクスをサポートしていません。このディレクティブの値 を False にセットすると、 Cython は負のインデクスのチェックや、イ ンデクスが負の時の適切な処理を行わなくなるので、注意してコードを書 かなければ、 segfault やデータの破損を引き起こすことがあります。デ フォルトの値は True です。
nonecheck (True / False)
False にセットすると、 Cython は、拡張型として定義されている変数の ネイティブのフィールドアクセスや、バッファの変数へのバッファインタ フェースへのアクセスを行う際、変数は決して None にはならないと みなします。False にセットしなければ、都度チェックの処理が挿入され、 チェックに失敗した場合には適切な例外を送出します。パフォーマンス上 の理由から、このディレクティブの値はデフォルトで False にセットさ れています。
embedsignature (True / False)
True にセットすると、 Cython は、 Python 側から見える関数やクラス の docstring に、関数の呼び出しシグネチャをテキストの形でコピーし て埋め込みます。それによって、 IPython や epydoc といったツール で、関数のシグネチャを表示できます。セットしなければ、コンパイル後 に関数シグネチャを参照できなくなります。デフォルト値は False です。
cdivision (True / False)
False にセットすると、Cython は C の型に対する除算・剰余演算子に関 する仕様を、(被演算子間の符号が異なる場合の振る舞いが異なる) Python の int の仕様に合わせ、除算する数が 0 の場合に ZeroDivisionError を送出します。この処理を行わせると、速度に 35% ぐらいのペナルティが生じます。 True にセットすると、チェックを 行いません。詳しくは CEP 516 を参照し てください。デフォルトの値は False です。
cdivision_warnings (True / False)
True にセットすると、 Cython は負の被演算子を使って除算を行うたび にランタイム警告を出力します。 CEP 516 を参照し てください。デフォルトの値は False です。
always_allow_keywords (True / False)
引数をもたない、あるいは一つしか引数を持たない関数やメソッドを生成 するときに、 METH_NOARGSMETH_O を使わないようにします。 二つ以上の引数を持つ特殊メソッドや関数には影響を及ぼしません。 METH_NOARGSMETH_O といったシグネチャには、キーワード引 数を使えないことと引き換えに、呼び出しが高速になるよう便宜が図られ ています。
profile (True / False)
C のコードに Python プロファイラへのフックを仕込んでコンパイルしま す。デフォルトの値は False です。
infer_types (True / False)
関数ボディ中で型付けされていない変数に対して型の推測を行います。 デフォルト値は None で、安全な型の推測 (セマンティクスを変えない: sematically-unchanging) のみ行わせます。
language_level (2/3)
モジュールのコンパイルに使う Python の言語レベルをグローバルにセッ トします。デフォルトの設定では、 Python 2 との互換性を残します。 Python 3 のソースコードセマンティクスを有効にするには、モジュール のヘッダコメントでこのディレクティブの値を 3 にセットするか、コン パイラのコマンドラインオプションに “-3” を渡して下さい。 コンパイル対象のモジュールでこのディレクティブを使うと、その設定値 は、cimport されたソースコードや include したソースファイルに引き 継がれます。ただし、明示的に各ファイルで言語レベルを指定した場合は、 引き継がれません。

ディレクティブの設定方法

グローバルな設定方法

コンパイラディレクティブは、以下のように、ファイルの先頭に特殊なヘッダ コメントとして設定できます:

#!python
#cython: boundscheck=False

コメントは、他のコードよりも前に置かねばなりません (他のコメントや空白 文字の後ろでもかまいません)。

また、コマンドラインに -X スイッチを使うと、ディレクティブを渡せま す:

$ cython -X boundscheck=True ...

コマンドラインで渡したディレクティブは、ヘッダコメントで定義したディレ クティブの設定をオーバライドします。

ローカルな設定方法

ローカルなブロックでの設定には、まず組み込みの cython モジュールを import します:

#!python
cimport cython

次に、以下のように、ディレクティブをデコレータとして使うか、実行文とし て定義します:

#!python
@cython.boundscheck(False) # この関数に対して boundscheck をオフにする
def f():
    ...
    with cython.boundscheck(True): # このブロックでのみ、 boundscheck を一時的にオンに戻す
        ...

Warning

これらの二つのディレクティブ設定方法は、 -X オプショ ンでディレクティブをオーバライドしても影響を 受けません