boost.python: how to pass a python object to C++ world and how to return a C++ created object to the python interpreter
この話はプログラム言語の話なのでこの話題に興味のない方はまたの機会にお会いしましょう.
私はこれまでスクリプティング言語として ruby を使ってきたのだが,industry では python という言語がさかんであるので,python も使ってみることにした.以前はプログラミング言語をかじった(ほとんど三日坊主でマスターしたものはあまりないが)ものだったが,最近はそんなでもない.年をとったものである.そこでちょっと皆のすなる python というものを私もかじってみることにした.
最初に,Marc Lutz の Learning Python を読んだ.(二週間弱かかった).なかなか面白いと思った.先週本を読み終えたので,今週はプログラム書いてみることにした.
Python には様々な入門の Page があるので,私が言語の話をしても読者はそんなに興味を持たれないであろう.そこでちょっと細かい話になるが,boost.python の話をしよう.現在私は boost.phthon を使ってあるライブラリを python に bind している.
boost.pythonは C++ のプログラムから Python interpreter を呼び出したり,Python のプログラムから C++ の関数を呼び出したりするためのコードを書くためのライブラリである.これを使うと Python の機能を拡張するというようなことができる.
boost.python のドキュメントある程度充実しているが,例題が多少乏しい感じがする.とはいっても,boost.python を使う人はそんなに多くないだろうから仕方ないことだろう.
次の例題(passobj_mod.cpp)は,Python interpreter から python のdictionary を私の C++ のobject に渡すことができるかのテストである.boost.python はとても良くできていて,そういうことが簡単に書けることがわかった.
---
/// passobj_mod.cpp: How to pass the python dict to the C++ fucntion/method.
///
/// Copyright (C) 2010 Shitohichi Umaya
///
/// test for using C++ class from python: pass a string or a dict to a
/// C++ method
#include <boost/python.hpp>
#include <boost/python/object.hpp>
#include <boost/python/extract.hpp>
#include <boost/python/list.hpp>
#include <boost/python/dict.hpp>
#include <boost/python/str.hpp>
#include <stdexcept>
#include <iostream>
/// using namespace only for example
using namespace boost::python;
/// C++ object which python can instantiate
class PassObj {
public:
/// constructor
PassObj()
{
// empty
}
/// pass a python object, but this should be a python dictionary.
/// \param[in] pydict a dictionary
void pass_dict(object pydict) const {
extract< dict > cppdict_ext(pydict);
if(!cppdict_ext.check()){
throw std::runtime_error(
"PassObj::pass_dict: type error: not a python dict.");
}
dict cppdict = cppdict_ext();
list keylist = cppdict.keys();
// careful with boost name. there already have a conflict.
int const len = boost::python::len(keylist);
std::cout << "len(keylist) = " << len << std::endl;
for(int i = 0; i < len; ++i){
// operator[] is in python::boost::object
std::string keystr = extract< std::string >(str(keylist[i]));
std::string valstr = extract< std::string >(str(cppdict[keylist[i]]));
std::cout << "key:[" << keystr << "]->[" << valstr << "]" << std::endl;
}
}
/// pass a python object, but this should be a python string.
/// \param[in] pydict a string
void pass_string(object pystr) const {
extract< std::string > cppstr_ext(pystr);
if(!cppstr_ext.check()){
throw std::runtime_error(
"PassObj::pass_str: type error: not a python string.");
}
std::string cppstr = cppstr_ext();
std::cout << "passed string: " << cppstr << std::endl;
}
/// return a dict object. Does this works?
/// \return a dict object
object return_dict() const {
dict cppdict;
cppdict["this"] = "work?";
cppdict["no"] = "idea";
cppdict["number"] = 1;
return cppdict;
}
/// return a dict object. Does this works?
/// \return a dict object
object return_string() const {
return str("Incredible, this works.");
}
private:
};
/// importing module name is 'passobj_mod'
BOOST_PYTHON_MODULE(passobj_mod)
{
class_<PassObj>("passobj")
.def("pass_dict",
&PassObj::pass_dict,
"pass python dict object to c++ method")
.def("pass_string",
&PassObj::pass_string,
"pass python string to c++ method")
.def("return_dict",
&PassObj::return_dict,
"return C++ created dict to python")
.def("return_string",
&PassObj::return_string,
"return C++ created str to python")
;
}
---
#
# test_passobj_mod.py
# test pass object module, python side implementation
# Copyright (C) 2010 Shitohichi Umaya
#
import passobj_mod
pobj = passobj_mod.passobj()
print dir(pobj)
pobj.pass_string('This is python string, can you hear me?')
pdict = {'pythondict': 1, 'foo': 'bar', 'Bach': 'Goldberg Variation' }
pobj.pass_dict(pdict)
dict_from_cpp = pobj.return_dict()
str_from_cpp = pobj.return_string()
---
#! /bin/sh -x
# build.sh
# Copyright (C) 2010 Shitohichi Umaya
#
PYTHON_INCLUDE=`python-config --includes`
MOD_CPP_SOURCE_BASE=passobj_mod
g++ ${PYTHON_INCLUDE} -DPIC -shared -fPIC ${MOD_CPP_SOURCE_BASE}.cpp -o ${MOD_CPP_SOURCE_BASE}.so -lboost_python
---
この test_passobj_mod.py は passobj_mod.cpp の PassObj の method を呼ぶテストである.build.sh は passobj_mod.so をビルドする sh script である.ファイルを作成して実行権限などを変更した後,以下のようにタイプする
# build.sh
# python test_passobj_mod.py
すると,実際に動かすことができるかと思う.動作確認は Ubuntu Linux 9.04 にて行なった.
さて,test_passobj_mod.py は本の例題などを除いた私のほぼ初めてのpython プログラムであることもあって class も def もないが,いつになってもプログラムが思ったように動いた時は楽しいものだと思う.