【C++ python】Boostを使用したpythonバインディング
2016/7/25
皆さん始めまして、開発の望月です。
ついに僕も「DF TALK」を執筆する大役を仰せつかったので、僭越ながら皆さんに情報を発信できればと思います。
さて、本日はboostを使用して、C++で書いたライブラリをpythonにバインディングするために、どうすれば良いかご紹介させて頂きます。
始めに
今回の実行環境は以下のようになります。ipythonなどを使用するとpythonでテストするときに楽です。
- Visual Studio 2010
- python 2.7
- Boost 1.61
Boostとは
端的に言うとC++の便利ライブラリのセットです。スマートポインタ、シリアライズ含め多くの便利な機能をオープンソースで使うことが出来ます。詳しくはwiki…
ライブラリの実績も多く、内部の設計においてもメタプログラミング盛りだくさんで勉強になります。
今回はBoostで提供されている、boost::pythonを使用してバインディングを行っていきます。
まずはHelloWorld
定番ですね。以下にソースと実行結果を示します。生成するdllの拡張子は「.pyd」に変更してpythonの実行環境に配置してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 | #define BOOST_PYTHON_STATIC_LIB //これが無いとboostに依存したDLLが出来ます。 #include <string> #include <boost/python.hpp> std::string helloBP() { return "Hello BoostPython" ; } BOOST_PYTHON_MODULE (BP) { boost::python::def( "hello" , helloBP ); } |
実行結果
いや~簡単ですね。では次はclassを定義してみましょう。
classもバインドしてみよう
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #define BOOST_PYTHON_STATIC_LIB #include <string> #include <boost/python.hpp> class boostPython{ public : boostPython():value(0){}; ~boostPython(){}; float value; void printValue(){std::cout << "value = " << value << std::endl;}; void addValue( const float &input){ value += input;}; }; BOOST_PYTHON_MODULE (BP) { boost::python::class_<boostPython>( "boostPython" ) .def ( "add" ,&boostPython::addValue) .def ( "printValue" ,&boostPython::printValue); } |
実行結果
変数も下記のようにすることで、読み書きできる形で公開出来ます。(読み込み専用も出来ます。)
1 2 3 4 5 6 7 | BOOST_PYTHON_MODULE (BP) { boost::python::class_<boostPython>( "boostPython" ) .def_readwrite( "value" ,&boostPython::value) .def ( "add" ,&boostPython::addValue) .def ( "printValue" ,&boostPython::printValue); } |
捗るな~
Operatorも出しちゃおう
最後はOperator(オペレーター)についてです。オレペーターではありません。
例えば「a += b」という式の「+=」の部分がOperatorになります。
独自のclassを設計した場合、Operatorを書いてあげる必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #define BOOST_PYTHON_STATIC_LIB #include <string> #include <boost/python.hpp> class boostPython{ public : boostPython():value(0){}; ~boostPython(){}; float value; boostPython operator+( const float &input){ this ->value += input; return * this ; }; boostPython& operator+=( const boostPython &input){ this ->value += input.value; return * this ; }; void printValue(){std::cout << "value = " << value << std::endl;}; void addValue( const float &input){ value += input;}; }; BOOST_PYTHON_MODULE (BP) { boost::python::class_<boostPython>( "boostPython" ) .def_readwrite( "value" ,&boostPython::value) .def ( "add" ,&boostPython::addValue) .def ( "printValue" ,&boostPython::printValue) .def (boost::python::self + float ()) .def (boost::python::self += boost::python::self); } |
実行結果
正しく計算できてますね。もちろん他のOperatorも定義できます。
最後に
いかがだったでしょうか。
pythonへのバインディングは別の方法も数多くありますが、boostを使うことでシンプルな実装にすることができると思います。ちなみに、今回は深く掘り下げませんが、並列化(OpenMP、TBB、CUDA、OpenCL等)も問題なく動きます。
最近のプログラム界ではまず軽量プログラミング言語でプロトタイピングを行ってから、
速度の必要な部分をC++とか高速な言語で書くといったような流れをひしひしと感じています。(3DCG系のDCCツールとかはpythonバインディングを当たり前のように提供してますし)
僕自身はpythonのハードユーザーではないんですが、やはり軽量言語の手軽さは良いですね。これからは”pythonista”になれるよう積極的に使っていこうと思います。
※免責事項※
本記事内で公開している全ての手法・コードの有用性、安全性について、当方は一切の保証を与えるものではありません。
これらのコードを使用したことによって引き起こる直接的、間接的な損害に対し、当方は一切責任を負うものではありません。
自己責任でご使用ください。
コメント
コメントフォーム