Cythonベースチュートリアル(5)-C++ライブラリをcythonでパッケージ
12143 ワード
C++ライブラリをcythonで包装
単純に乱数を生成するクラスがあると仮定し、インタフェースを提供します.
Cythonはpublicメソッドとメンバーのみをパッケージでき、privatedまたはprotectedメソッドとメンバーにアクセスできません.Cythonでこのクラスインタフェースを使用するには、externキーワードを使用するには、3つの要件があります. Declaring the c++ namespace with cython namespace clause Using the cppclass keyword to declare a C++ class interface block Declaring the class’s interface in this block
だってMT_RNGはmtrandomネーミングスペースで宣言され、cythonでcdef externを使用するにはネーミングスペースを説明する必要があります.externコードの速い内部で定数Nを宣言し、cppclassキーワードでMT_を宣言します.RNG c++クラスで、そのクラスの内部には、cythonで使用したいPublic構造体、関数、クラスメンバーをすべて入れて、Cythonコードにアクセスできます.
cythonでは、c++クラスを拡張タイプでパッケージするのが一般的です.拡張タイプRNGを定義し、この拡張タイプには、包装されたc++クラスを指すポインタがあり、_cinit__方式で初期化を行い、_dealloc__メモリ回収を行います.dealloc__プログラムが終了したときにのみ使用され、一度だけ呼び出されます.クラスメンバー関数のいくつかをcpdefで定義して乱数を生成できます(_thisptrポインタを介して).次に、c++クラスをパッケージする例を示します.
コンパイル
c++プロジェクトをコンパイルするときは、c++言語を使用し、c++のソースファイルを含むことを説明する必要があります.例えば、RNGをコンパイルする.pyxファイル、setupを新規作成する必要があります.py、含まれるコードは次のとおりです.
リロード関数とメソッド
MT_の場合RNGクラスでは、異なるパラメータが異なる構造関数に対応していますが、pythonでは、どのように呼び出すのでしょうか.pythonは関数のリロードをサポートしていないため、_cinit__に表示する情報を制限しました.このため、python標準ライブラリの内蔵array(内蔵要素タイプが同じであることが必要)が必要です.cythonはpythonとc++でarrayタイプの変数を処理する方法を知っています.
cythonコードで直接C++クラスを使用
拡張タイプでc++クラスをパッケージする方法を知っています.これもcythonでc++クラスを使用する最も一般的な方法です.もちろん、Cythonコードの中で直接C++クラスを使うこともできます.stack-allocateを使ってMT_を1つ使うことができます.RNGインスタンスは、プログラムの終了時にこのインスタンスをクリーンアップする.c++オブジェクトを使用するには、cef cppclassコードブロックで宣言する必要があります.
関数でMT_をRNGオブジェクトはいくつかの操作を行う
単純に乱数を生成するクラスがあると仮定し、インタフェースを提供します.
namespace mtrandom {
const static unsigned int N = 624;
class MT_RNG {
public:
MT_RNG();
MT_RNG(unsigned long s);
MT_RNG(unsigned long init_key[], int ket_length);
void init_genrand(unsigned long s);
unsigned long genrand_int32();
double genrand_real1();
private:
unsigned long mt[N];
int mti;
};
}
Cythonはpublicメソッドとメンバーのみをパッケージでき、privatedまたはprotectedメソッドとメンバーにアクセスできません.Cythonでこのクラスインタフェースを使用するには、externキーワードを使用するには、3つの要件があります.
だってMT_RNGはmtrandomネーミングスペースで宣言され、cythonでcdef externを使用するにはネーミングスペースを説明する必要があります.externコードの速い内部で定数Nを宣言し、cppclassキーワードでMT_を宣言します.RNG c++クラスで、そのクラスの内部には、cythonで使用したいPublic構造体、関数、クラスメンバーをすべて入れて、Cythonコードにアクセスできます.
cdef extern from "mt19937.h" namespace "mtrandom":
unsigned int N
cdef cppclass MT_RNG:
MT_RNG(unsigned long s)
MT_RNG(unsigned long init_key[], int key_length)
void init_genrand_int32()
unsigned long genrand_int32()
double genrand_real1()
cythonでは、c++クラスを拡張タイプでパッケージするのが一般的です.拡張タイプRNGを定義し、この拡張タイプには、包装されたc++クラスを指すポインタがあり、_cinit__方式で初期化を行い、_dealloc__メモリ回収を行います.dealloc__プログラムが終了したときにのみ使用され、一度だけ呼び出されます.クラスメンバー関数のいくつかをcpdefで定義して乱数を生成できます(_thisptrポインタを介して).次に、c++クラスをパッケージする例を示します.
cdef class RNG:
cdef MT_RNG *_thisptr
def __cinit__(self, unsigned long s):
self._thisptr = new MT_RNG(S)
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()
コンパイル
c++プロジェクトをコンパイルするときは、c++言語を使用し、c++のソースファイルを含むことを説明する必要があります.例えば、RNGをコンパイルする.pyxファイル、setupを新規作成する必要があります.py、含まれるコードは次のとおりです.
from distutils.core import setup, Extension
from Cython.Build import cythonize
ext = Extension("RNG", source=['RNG.pyx', 'mt19937.cpp'], language='c++')
setup(name="RNG", ext_modules=cythonize(ext))
リロード関数とメソッド
MT_の場合RNGクラスでは、異なるパラメータが異なる構造関数に対応していますが、pythonでは、どのように呼び出すのでしょうか.pythonは関数のリロードをサポートしていないため、_cinit__に表示する情報を制限しました.このため、python標準ライブラリの内蔵array(内蔵要素タイプが同じであることが必要)が必要です.cythonはpythonとc++でarrayタイプの変数を処理する方法を知っています.
from cython.array import array
cdef class RNG:
cdef MT_RNG *_thisptr
def __cinit__(self, seed_or_state):
if isinstance(seed_or_state, int):
self._thisptr = new MT_RNG(seed_or_state)
else:
state_arr = array("L", seed_or_state)
self._thisptr = new MT_RNG(state_arr.data.as_ulongs, len(state_Arr))
cythonコードで直接C++クラスを使用
拡張タイプでc++クラスをパッケージする方法を知っています.これもcythonでc++クラスを使用する最も一般的な方法です.もちろん、Cythonコードの中で直接C++クラスを使うこともできます.stack-allocateを使ってMT_を1つ使うことができます.RNGインスタンスは、プログラムの終了時にこのインスタンスをクリーンアップする.c++オブジェクトを使用するには、cef cppclassコードブロックで宣言する必要があります.
cdef extern from "mt19937.h" namespace "mtrandom":
cdef cppclass MT_RNG:
MT_RNG()
void init_genrand(unsigned long s)
関数でMT_をRNGオブジェクトはいくつかの操作を行う
def make_random_list(unsigned long seed, unsigned int len):
cdef:
#...
MT_RNG *rng
rng = new MT_RNG(seed)
try:
#...
finally:
del rng