他人のソースを動かしていると、.pyxというファイルがあって、これ何?と思ったから調べてみた。
.pyxの拡張子とは、PythonをC言語ライクにコンパイルするCythonというメタ言語のスクリプトファイルのこと。つまり、Cythonっていうほぼpythonみたいな言語があって、それが書かれたファイルってことらしい。
Cythonについて興味が湧いてきたので少し掘り下げてみた。
Cython は、C言語によるPythonの拡張モジュールの作成の労力を軽減することを目的として開発されたプログラミング言語である。その言語仕様はほとんど Python のものと同じ (上位互換) だが、Cの関数を直接呼び出したり、C言語の変数の型やクラスを宣言できるなどの拡張が行われている。Cython の処理系ではソースファイルを C のコードに変換し、コンパイルすれば Python の拡張モジュールになるようにして出力する。
Wikipediaより
要は、Pythonをcみたいに高速化したい!って時とかcの関数をPythonで使いたい!って時に使うっぽい。
今回は簡単なチュートリアルを試してみて、Cの関数をPythonで使うサンプルを書いてみることにした。
以下、Cythonのチュートリアル。
Hello world!
Cythonのビルド
実際にやってみる
- hello.pyx
print('Hello World!')
- setup.py
from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext setup( cmdclass = {'build_ext': build_ext}, ext_modules = [Extension("helloworld", ["helloworld.pyx"])] )
この時点ではこの二つのファイルしかない
>>ls hello.pyx setup.py
以下のコマンドでビルド。
python setup.py build_ext --inplace
すると色んなファイルができている。
>>ls build/ hello.c hello pyx hello.so setup.py
試しに同じディレクトリでimportを実行してみると...
>>> import hello Hello World!
できた!
Cのビルトイン関数を使ってみる
cythonでcで書かれた関数を読めるのか疑問に思ったので
cで書かれた関数をpythonでimportするところまでやってみる。
pythonのimportと違ってcthonでcのライブラリをimportするときはcimportを使う。
例えば、math.hを使うときはこのようにする。
- csin.pyx
from libc.math cimport sin cdef double c_sin(double x): return sin(x) def get_c_sin(x): return c_sin(x)
ちなみに、標準で cimport できるファイルの一覧は、 Cython のソースパッケージの Cython/Includes/ の下を見れば分かる。
Anacondaを使っている環境では
~/anaconda2/pkgs/cython-0.24.1-py27_0/lib/python2.7/site-packages/Cython/Includes/
にあった。
setup.pyはそのまま"csin.pyx"を追加するだけでもいいかと思ったが、
一部のUnixシステムでは数学ライブラリをデフォルトでリンクしないので、共有ライブラリ m へのリンクを設定しなければいけないらしい。
(C の関数を呼び出す — Cython 0.17.1 documentation)
- setup.py
from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext setup( cmdclass = {'build_ext':build_ext}, ext_modules = [Extension("hello",["hello.pyx"]), Extension("csin",["csin.pyx"],libraries=["m"])], )
さっきと同じようにビルドしてやると…
>>> import csin >>> csin.get_c_sin(1) 0.8414709848078965
できた!
※
ちなみに、
>>>csin.c_sin(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'c_sin'
は実行できなかった
cdefで宣言した関数は呼び出せないのか???
参考サイト: