jineff jineff - 1 month ago 14
C++ Question

Exposing a C++ class instance to a python embedded interpreter

I am looking for a simple way to expose a C++ class instance to a python embedded interpreter.


  • I have a C++ library. This library is wrapped (using swig for the moment) and I am able to use it from the python interpreter

  • I have a C++ main program which instanciates a Foo class from my library and embeds a python interpreter



I would like to expose my C++ world instance of Foo to the python world (and seen as a Foo class).

Is this possible, if so, how?

I think it's almost like in the first answer of :
boost::python::ptr or PyInstance_New usage

I guess this means I should use
boost.Python
to wrap my library?


My only goal is to manipulate my C++ instance of Foo in the embedded python interpreter (not sure that it can be done with the previous method).

Hope I am clear, thanks for your help.

update

Thanks for your answers. In fact, I already have exposed my Foo class to python (with swig).

What I have:

my Foo class:

class Foo{...};


my wrapped library (including the Foo class) exposed to python: so I can start the python interpreter and do something like this :

import my_module
foo=my_modulde.Foo()


What I want:

Having a C++ main program which embeds a python interpreter and manipulates C++ world variables.

int main(int argc, char **argv)
{
Foo foo; // instanciates foo

Py_Initialize();

Py_Main(argc, argv); // starts the python interpreter
// and manipulates THE foo instance in it

Py_Finalize();

return 0;
}


Clearer now ? :)

Answer

Boost python Allows you to expose c++ classes to python in a very tightly integrated way - you can even wrap them so that you can derive python classes from your c++ ones, and have virtual methods resolved to the python overrides.

The boost python tutorial is a good place to start.


edit:

You can create a c++ object and pass a reference to it to an internal python interpreter like this:

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/python.hpp>
#include <string>
#include <iostream>

namespace bp = boost::python;

struct Foo{
    Foo(){}
    Foo(std::string const& s) : m_string(s){}
    void doSomething() {
        std::cout << "Foo:" << m_string << std::endl;
    }
    std::string m_string;
};

typedef boost::shared_ptr<Foo> foo_ptr;

BOOST_PYTHON_MODULE(hello)
{
    bp::class_<Foo, foo_ptr>("Foo")
        .def("doSomething", &Foo::doSomething)
    ;
};

int main(int argc, char **argv)
{
    Py_Initialize();
    try {
        PyRun_SimpleString(
            "a_foo = None\n"
            "\n"
            "def setup(a_foo_from_cxx):\n"
            "    print 'setup called with', a_foo_from_cxx\n"
            "    global a_foo\n"
            "    a_foo = a_foo_from_cxx\n"
            "\n"
            "def run():\n"
            "    a_foo.doSomething()\n"
            "\n"
            "print 'main module loaded'\n"
        );

        foo_ptr a_cxx_foo = boost::make_shared<Foo>("c++");

        inithello();
        bp::object main = bp::object(bp::handle<>(bp::borrowed(
            PyImport_AddModule("__main__")
        )));

        // pass the reference to a_cxx_foo into python:
        bp::object setup_func = main.attr("setup");
        setup_func(a_cxx_foo);

        // now run the python 'main' function
        bp::object run_func = main.attr("run");
        run_func();
    }
    catch (bp::error_already_set) {
        PyErr_Print();
    }

    Py_Finalize();

    return 0;
}