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
#include
#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#pyth...
return python::callstd::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_ 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(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();
}