Boost logo

Boost Users :

From: Neil Fang (neilfang2009_at_[hidden])
Date: 2008-08-19 22:43:41


I'm trying embedding python using boost::python. Just as the same way
as the boost::python quick start "embedding.cpp".
I have a C++ base class, with a virtual function do something on
another C++ object:
struct MyClass
{
        void printThis()
        {
                std::cout << "0x" << this << std::endl;
        }
};

// An abstract base class
class Base : public boost::noncopyable
{
public:
        virtual ~Base() {};
        virtual void printMyClass(MyClass& myObj) = 0;
};

Than, I want to write some Python derived class code:
"from embedded_hello import * \n"
"class PythonDerived(Base): \n"
" def printMyClass(self, myObj): \n"
" myObj.printThis() \n"

But I found that the "myObj" passed to python code is another obj, not
the object created in C++ code. How can use the object created in C++
object rather than a copyed object? Thanks!

The full code list below, which is modified form boost::python example.

// Copyright Stefan Seefeld 2005.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <boost/python.hpp>

#include <boost/detail/lightweight_test.hpp>
#include <iostream>

namespace python = boost::python;

struct MyClass
{
        void printThis()
        {
                std::cout << "0x" << this << std::endl;
        }
};

// An abstract base class
class Base : public boost::noncopyable
{
public:
  virtual ~Base() {};
  virtual std::string hello() = 0;
  virtual void printMyClass(MyClass& myObj) = 0;
};

// C++ derived class
class CppDerived : public Base
{
public:
  virtual ~CppDerived() {}
  virtual std::string hello() { return "Hello from C++!";}
  virtual void printMyClass(MyClass& myObj)
  {
          myObj.printThis();
  }
};

// Familiar Boost.Python wrapper class for Base
struct BaseWrap : Base, python::wrapper<Base>
{
        virtual void printMyClass(MyClass& myObj)
        {
                this->get_override("printMyClass")(myObj);
        }

  virtual std::string hello()
  {
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
    // workaround for VC++ 6.x or 7.0, see
    // http://boost.org/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions
    return python::call<std::string>(this->get_override("hello").ptr());
#else
    return this->get_override("hello")();
#endif
  }
};

// Pack the Base class wrapper into a module
BOOST_PYTHON_MODULE(embedded_hello)
{
  python::class_<BaseWrap, boost::noncopyable> base("Base");

  python::class_<MyClass>("MyClass")
          .def("printThis", &MyClass::printThis)
          ;
}

void exec_test()
{
    std::cout << "registering extension module embedded_hello..." << std::endl;

  // Register the module with the interpreter
  if (PyImport_AppendInittab("embedded_hello", initembedded_hello) == -1)
    throw std::runtime_error("Failed to add embedded_hello to the
interpreter's "
                 "builtin modules");

  std::cout << "defining Python class derived from Base..." << std::endl;

  // Retrieve the main module
  python::object main = python::import("__main__");

  // Retrieve the main module's namespace
  python::object global(main.attr("__dict__"));

  // Define the derived class in Python.
  python::object result = python::exec(
    "from embedded_hello import * \n"
    "class PythonDerived(Base): \n"
    " def hello(self): \n"
    " return 'Hello from Python!' \n"
        " def printMyClass(self, myObj): \n"
        " myObj.printThis() \n"
        ,
    global, global);

  python::object PythonDerived = global["PythonDerived"];

  MyClass myObj;
  // Creating and using instances of the C++ class is as easy as always.
  CppDerived cpp;
  BOOST_TEST(cpp.hello() == "Hello from C++!");
  cpp.printMyClass(myObj);

  std::cout << "testing derived class from C++..." << std::endl;

  // But now creating and using instances of the Python class is almost
  // as easy!
  python::object py_base = PythonDerived();
  Base& py = python::extract<Base&>(py_base) BOOST_EXTRACT_WORKAROUND;

  // Make sure the right 'hello' method is called.
  BOOST_TEST(py.hello() == "Hello from Python!");

  py.printMyClass(myObj);

  std::cout << "success!" << std::endl;
}

void exec_file_test(std::string const &script)
{
    std::cout << "running file " << script << "..." << std::endl;

    // Run a python script in an empty environment.
    python::dict global;
    python::object result = python::exec_file(script.c_str(), global, global);

    // Extract an object the script stored in the global dictionary.
    BOOST_TEST(python::extract<int>(global["number"]) == 42);

    std::cout << "success!" << std::endl;
}

void exec_test_error()
{
    std::cout << "intentionally causing a python exception..." << std::endl;

    // Execute a statement that raises a python exception.
    python::dict global;
    python::object result = python::exec("print unknown \n", global, global);

    std::cout << "Oops! This statement should be skipped due to an
exception" << std::endl;
}

int main(int argc, char **argv)
{
  //BOOST_TEST(argc == 2);
  //std::string script = argv[1];
  // Initialize the interpreter
  Py_Initialize();

  bool error_expected = false;

  if ( python::handle_exception(exec_test) )
  {
    if (PyErr_Occurred())
    {
        if (!error_expected)
            BOOST_ERROR("Python Error detected");
        PyErr_Print();
    }
    else
    {
        BOOST_ERROR("A C++ exception was thrown for which "
                    "there was no exception translator registered.");
    }
  }

  std::cin.get();
  // Boost.Python doesn't support Py_Finalize yet, so don't call it!
  return boost::report_errors();
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net