Skip to main content

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.

Comments

Popular posts from this blog

Why parallelogram area is |ad-bc|?

Here is my question. The area of parallelogram is the difference of these two rectangles (red rectangle - blue rectangle). This is not intuitive for me. If you also think it is not so intuitive, you might interested in my slides. I try to explain this for hight school students. Slides:  A bit intuitive (for me) explanation of area of parallelogram  (to my site, external link) . 

Geometric Multiplicity: eignvectors (2)

If eigenvectors of a matrix A are independent, it is a happy property. Because the matrix A can be diagonalized with a matrix S that column vectors are eigenvectors of A . For example, Why this is a happy property of A? Because I can find A's power easily. A^{10} is not a big deal. Because Λ is a diagonal matrix and power of a diagonal matrix is quite simple. A^{10} = SΛ^{10} S^{-1} Then, why if I want to compute power of A ? That is the same reason to find eigenvectors. Eigenvectors are a basis of a matrix. A matrix can be represented by a single scalar. I repeat this again. This is the happy point, a matrix becomes a scalar. What can be simpler than a scalar value. But, this is only possible when the matrix S's columns are independent. Because S^{-1} must be exist. Now I come back to my first question. Is the λ's multiplicity related with the number of eigenvectors? This time I found this has the name. Geometric multiplicity (GM): the number of in...

Tezuka Osamu's Black Jack, "Shrinking"

I like several novel authors. My first favorite author is probably Teduka, Osamu. I still love him. The list grows by adding Hoshi, Shinichi, Agatha Christie, Hermann Hesse, and so forth. My first favorite article of Tezuka was Atom as most of the (boy's) Tezuka fans did. But my favorite is Black Jack. I try to summarize one story, it is still quite vivid in my memory. I first read this story when I was 13 - 15 years old. I re-read it at least several times since Black Jack is composed of many short episodes. The title should be "ちぢむ (SHRINKING)" or it might be "縮む(Shrinking)". (It is not so convenient to translate this to English, since English does not have a system to say the exact same word in several ways. So I just simulate it with capital letters.) Black Jack is a genius surgeon, but he does not have the license. In short, his medical activity is illegal. His skill is top level in the world, but, the fee is also out-of-law expensive. In the story ...