boost.python: how to pass a python object to C++ world and how to return a C++ created object to the python interpreter
This is a programming language story. If you are not interested in such theme, see you other time...
I usually use ruby for scripting, however, in industry python is quite widely used. When I was a student, I was just interested in programming languages, yet I just interested in them for a few weeks and I did not use most of them. But, recently I even did not look into, I feel I become old... This time, I will try what so called ''python.'' (In my Japanese Web, this is ''皆のすなる python というものを,'' this is beginning of Tosa-nikki by Kino Turayuki, established around 935. Sadly, I can not translate this well by my poor English skill.)
First I read a book, Learning Python by Marc Lutz. I took around two weeks, it is fun and I find python interesting. Then this week, I started to implement a program.
There are a lot of introduction web pages of python, so, it is not worth to add something similar to the net, the readers will be also bored such blog entry. Therefore, I will go into a bit detail. I will write about boost.python. This week, I am developing a python binding of a C++ library using boost.python.
boost.python is a library that you can call python interpreter from C++ or you can call C++ function from python interpreter. I would like to extend python with binding a C++ library.
The documentation of boost.python is quite well, but the examples are a bit less. Although, not so many people use boost.python compared with usual python users. I think the documentation is well done considering that. I hope the following my code would fill this gap a bit.
The code (passobj_mod.cpp) is an example how to pass a python dictionary from the interpreter to C++ code, and also pass a C++ created object to the python interpreter. I find boost.python itself is amazingly well designed and developed. I can easily implement these kind of task, though I took a day to find how to do that.
---
/// 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 is a test example to call the methods of PassObj in passobj_mod.cpp. build.sh is a sh script to build the python module passobj_mod.so. If you create the files (with chmod) and type:
# build.sh
# python test_passobj_mod.py
then, I hope you can try that. I tested this on Ubuntu Linux 9.04.
This is my first python script except the examples in the book. There is no class, no def. However, I still find a fun to write a program and it is always rewarding a program runs as I expected.
I usually use ruby for scripting, however, in industry python is quite widely used. When I was a student, I was just interested in programming languages, yet I just interested in them for a few weeks and I did not use most of them. But, recently I even did not look into, I feel I become old... This time, I will try what so called ''python.'' (In my Japanese Web, this is ''皆のすなる python というものを,'' this is beginning of Tosa-nikki by Kino Turayuki, established around 935. Sadly, I can not translate this well by my poor English skill.)
First I read a book, Learning Python by Marc Lutz. I took around two weeks, it is fun and I find python interesting. Then this week, I started to implement a program.
There are a lot of introduction web pages of python, so, it is not worth to add something similar to the net, the readers will be also bored such blog entry. Therefore, I will go into a bit detail. I will write about boost.python. This week, I am developing a python binding of a C++ library using boost.python.
boost.python is a library that you can call python interpreter from C++ or you can call C++ function from python interpreter. I would like to extend python with binding a C++ library.
The documentation of boost.python is quite well, but the examples are a bit less. Although, not so many people use boost.python compared with usual python users. I think the documentation is well done considering that. I hope the following my code would fill this gap a bit.
The code (passobj_mod.cpp) is an example how to pass a python dictionary from the interpreter to C++ code, and also pass a C++ created object to the python interpreter. I find boost.python itself is amazingly well designed and developed. I can easily implement these kind of task, though I took a day to find how to do that.
---
/// 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 is a test example to call the methods of PassObj in passobj_mod.cpp. build.sh is a sh script to build the python module passobj_mod.so. If you create the files (with chmod) and type:
# build.sh
# python test_passobj_mod.py
then, I hope you can try that. I tested this on Ubuntu Linux 9.04.
This is my first python script except the examples in the book. There is no class, no def. However, I still find a fun to write a program and it is always rewarding a program runs as I expected.
Comments