[C++-sig] Creating an instance of a Python class in C++: PyRun_String?

Dirk Gerrits dirk at gerrits.homeip.net
Thu Nov 14 22:39:05 CET 2002


Hi.

I have an abstract base class and one concrete derivative in C++ and I 
have wrapped the base class with Boost.Python. Now I want to define 
another derived class, but I want to do this in Python. With the 
Boost.Python wrapper, this is easy. But now comes the hard part: I want 
to create an instance of this Python class and use it in C++.

The first thing I did was searching the latest posts on this mailing 
list which gave me 2 clues:
  - the example at the bottom of: 
http://www.boost.org/libs/python/doc/v2/extract.html
  - PyRun_String

Here's what I came up with:

#include <iostream>

// The abstract base class
class Base
{
public:
     virtual ~Base() {};

     virtual void f() = 0;
};

// The C++ derived class
class CppDerived : public Base
{
public:
     virtual ~CppDerived() {}

     void f()
     {
         std::cout << "CppDerived::f()\n";
     }
};

//-------------------------------------------------------//
#include <boost/python.hpp>
#include <boost/python/extract.hpp>
namespace python = boost::python;

namespace
{
     // Boost.Python wrapper for Base
     struct BaseWrap : public Base
     {
         BaseWrap(PyObject* self_)
             : self(self_) {}

         void f() { return python::call_method<void>(self, "f"); }

         PyObject* self;
     };

}

BOOST_PYTHON_MODULE(pythontest)
{
     python::class_<Base, BaseWrap, boost::noncopyable>("Base", 
python::no_init)
         ;
}
//-------------------------------------------------------//

int main()
{
     // Register the wrapper module
     PyImport_AppendInittab("pythontest", initpythontest);

     // Initialize the interpreter
     Py_Initialize();

     // Create and use an instance of the C++ derived class
     boost::shared_ptr<Base> cpp(new CppDerived);
     cpp->f();

     // Define the Python derived class
     PyRun_SimpleString(
         "from pythontest import *\n"
         "class PythonDerived(Base):\n"
         "    def __init__(self):\n"
         "        pass\n"
         "    def f(self):\n"
         "        print \"PythonDerived::f()\"\n"
     );

     // Create and use an instance of the Python derived class
     Base& py = python::extract<Base&>(
         PyRun_String("PythonDerived()\n", ???, ???, ???);
     py.f();

     std::cout << "\nPress <enter> to quit...";
     std::cin.get();

     // Release the Python interpreter
     Py_Finalize();
}

I feel like I'm almost there, but I just can't get this to work.

Firstly, I don't know which arguments to feed into PyRun_String. The 
python.org docs didn't really help me that much: I don't have any 
dictionaries of globals and locals, and what exactly is a start token? I 
tried 0s for all 3 arguments and then compiling, but that brought me to 
the second issue:

The 'Base& py = ...' line gave a compilation error saying that a 
python::extract<Base > could not be converted to a Base&. Then I tried 
replacing both Base& with Base*, which compiled but gave an access 
violation.

Can anyone help me out?

Thanks in advance,
Dirk Gerrits







More information about the Cplusplus-sig mailing list