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 A^{T}A is invertible? (2) Linear Algebra

Why A^{T}A has the inverse Let me explain why A^{T}A has the inverse, if the columns of A are independent. First, if a matrix is n by n, and all the columns are independent, then this is a square full rank matrix. Therefore, there is the inverse. So, the problem is when A is a m by n, rectangle matrix.  Strang's explanation is based on null space. Null space and column space are the fundamental of the linear algebra. This explanation is simple and clear. However, when I was a University student, I did not recall the explanation of the null space in my linear algebra class. Maybe I was careless. I regret that... Explanation based on null space This explanation is based on Strang's book. Column space and null space are the main characters. Let's start with this explanation. Assume  x  where x is in the null space of A .  The matrices ( A^{T} A ) and A share the null space as the following: This means, if x is in the null space of A , x is also in the n...

Gauss's quote for positive, negative, and imaginary number

Recently I watched the following great videos about imaginary numbers by Welch Labs. https://youtu.be/T647CGsuOVU?list=PLiaHhY2iBX9g6KIvZ_703G3KJXapKkNaF I like this article about naming of math by Kalid Azad. https://betterexplained.com/articles/learning-tip-idea-name/ Both articles mentioned about Gauss, who suggested to use other names of positive, negative, and imaginary numbers. Gauss wrote these names are wrong and that is one of the reason people didn't get why negative times negative is positive, or, pure positive imaginary times pure positive imaginary is negative real number. I made a few videos about explaining why -1 * -1 = +1, too. Explanation: why -1 * -1 = +1 by pattern https://youtu.be/uD7JRdAzKP8 Explanation: why -1 * -1 = +1 by climbing a mountain https://youtu.be/uD7JRdAzKP8 But actually Gauss's insight is much powerful. The original is in the Gauß, Werke, Bd. 2, S. 178 . Hätte man +1, -1, √-1) nicht positiv, negative, imaginäre (oder gar um...

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) .