注意 以下の記事は古くなっています。
pybind11の使用を検討してください。
「Cython Cとの融合によるPythonの高速化」オライリーから
C++言語で書かれた関数をPythonでimportして実行できることをUbuntu上でたどってみた。
まずは、この本のサンプルがgithub上にあるのでzipファイルでまとめてダウンロードする。
https://github.com/cythonbook/examples
展開してできたディレクトリに移動する。
examples-master/08-wrapping-cxx/01-simple-example-mt_rng-class
C++で書かれたソースコード
mt19937.h
mt19937.cpp
Cythonにおける外部Cコードの宣言(拡張子 .pxd)
C++クラスのラップ(拡張子 .pyx)
# distutils: language = c++
# distutils: sources = mt19937.cpp
cdef extern from "mt19937.h" namespace "mtrandom":
unsigned int N
cdef cppclass MT_RNG:
MT_RNG()
MT_RNG(unsigned long s)
MT_RNG(unsigned long init_key[], int key_length)
void init_genrand(unsigned long s)
unsigned long genrand_int32()
double genrand_real1()
double operator()()
cdef class RNG:
cdef MT_RNG *_thisptr
def __cinit__(self, unsigned long s):
self._thisptr = new MT_RNG(s)
if self._thisptr == NULL:
raise MemoryError()
def __dealloc__(self):
if self._thisptr != NULL:
del self._thisptr
cpdef unsigned long randint(self):
return self._thisptr.genrand_int32()
cpdef double rand(self):
return self._thisptr.genrand_real1()
コンパイルの方法を指示するsetup.pyファイル
from distutils.core import setup, Extension
from Cython.Build import cythonize
ext = Extension("RNG",
sources=["RNG.pyx", "mt19937.cpp"],
language="c++")
setup(name="RNG",
ext_modules=cythonize(ext))
ここから後は、Cythonの解釈を試みているが間違っている可能性があるので
同書を参考してください。
Cythonにおける外部C++コードの宣言(拡張子 .pxd)
cdef extern from "C++でのヘッダファイル" namespace "C++での名前空間":
C++のヘッダファイルの中でconst static で定義されている定数
unsigned int N
cdef cppclass C++でのクラス識別子:
コンストタクタ()
コンストタクタ(unsigned long s)
コンストタクタ(unsigned long init_key[], int key_length)
publicのメソッドのうちCythonで利用するC++のメソッドの宣言
void init_genrand(unsigned long s)
unsigned long genrand_int32()
double genrand_real1()
double operator()()
githubからダウンロードしたファイルでは、Cythonにおける外部C++コードの宣言は
pyxファイルに移行していること。
pyxファイルにC++言語であることを指定する記述が追加
# distutils: language = c++
cdef cppclass MT_RNG:
のブロックの記述で、参照元のC++でのクラスとpublicのメソッドの定義を記述している。
cdef class Cythonでのクラスの識別子:
cdef MT_RNG *_thisptr
def __cinit__(self, unsigned long s):
コンストラクタの記述
この中でwrapする対象のC++のクラスのインスタンスを生成する。
引数の最初selfはPythonのクラスの場合と共通。
self._thisptr = new MT_RNG(s)
if self._thisptr == NULL:
raise MemoryError()
def __dealloc__(self):
クリーンアップを行う特殊メソッド
if self._thisptr != NULL:
del self._thisptr
cpdef Cythonでの型 メソッド名(self, 引数):
Cythonの文法でのメソッドの実装
この中では、cdef externで宣言したC++の関数やメソッドが利用できる。
return 戻り値
cpdef unsigned long randint(self):
return self._thisptr.genrand_int32()
cpdef double rand(self):
return self._thisptr.genrand_real1()
from distutils.core import setup, Extension
from Cython.Build import cythonize
ext = Extension("python拡張モジュールの名前",
sources=["pyxファイルの名前", "cppファイルの名前"],
language="c++")
setup(name="RNG",
ext_modules=cythonize(ext))
C版との違い:
ext = Extension()にlanguage="c++"が追加されたこと。
補足:
Cレベル言語要素の宣言をpxdファイルではなくて、pyxファイルに含めることも可能であること。
しかし、メンテナンスのためにはpxdファイルとして別ものにした方がよいこと。
ためしに、
cdef extern from "mt19937.h" namespace "mtrandom":
で始まるブロックをpyxファイルからpydファイルに抜き出してコンパイルしても
buildと動作に成功した。
URL:
Cython ドキュメント(和訳) チュートリアル
http://omake.accense.com/static/doc-ja/cython/src/tutorial/index.html