如何使用 boost::python 创建和使用 Python 对象的实例
How to Create and Use Instance of a Python Object with boost::python
假设我有一个 Python class 像这样:
class MyPythonClass:
def Func1(self, param):
return
def Func2(self, strParam):
return strParam
如果我想在我的 C++ 代码中嵌入包含 class 的 Python 脚本,请通过我的 C++ 代码创建该对象的实例,然后调用该 python 对象,我该怎么做?
我认为它会是这样的:
namespace python = boost::python;
python::object main = python::import("main");
python::object mainNamespace = main.attr("__dict__");
python::object script = python::exec_file(path_to_my_script, mainNamespace);
python::object foo = mainNamespace.attr("MyPythonClass")();
python::str func2return = foo.attr("Func2")("hola");
assert(func2return == "hola");
但是我尝试过此代码的许多变体都没有奏效。为了能够做到这一点,我需要在我的代码中加入什么神奇的调味料?
这就是最终对我有用的方法。
namespace python = boost::python;
python::object main = python::import("main");
python::object mainNamespace = main.attr("__dict__");
//add the contents of the script to the global namespace
python::object script = python::exec_file(path_to_my_script, mainNamespace);
//add an instance of the object to the global namespace
python::exec("foo = MyPythonClass()", mainNamespace);
//create boost::python::object that refers to the created object
python::object foo = main.attr("foo");
//call Func2 on the python::object via attr
//then extract the result into a const char* and assign it to a std::string
//the last bit could be done on multiple lines with more intermediate variables if desired
const std::string func2return = python::extract<const char*>(foo.attr("Func2")("hola"));
assert(func2return == "hola");
如果有更好的方法,欢迎留言评论。
下面是一个使用 Boost::python 嵌入的例子。我特别喜欢这种方法,因为使用 python class 函数就像在 python 中一样简单。但是,它确实需要一些设置。
#include <boost/python.hpp>
// An abstract base class
class Base : public boost::noncopyable
{
public:
virtual ~Base() {};
virtual void func1() = 0;
virtual std::string func2(std::string strParam) = 0;
}
// Boost.Python wrapper class for Base
// a function pointer to Base::hello and then calls function
struct BaseWrap : Base, python::wrapper<Base>
{
virtual void func1()
{
this->get_override("func1")();
}
virtual void func2(std::string strParam)
{
std::string str = this->get_override("func2")(strParam);
return str;
}
}
// Pack the Base class wrapper into a module
BOOST_PYTHON_MODULE(embedded_py)
{
//creating p c++ class instance called "base" and constructed with "Base"
python::class_<BaseWrap, boost::noncopyable> base("Base");
}
int main()
{
Py_Initialize();
std::cout << "registering extension module embedded_py ..." << std::endl;
// Register the module with the interpreter
if (PyImport_AppendInittab("embedded_pi", initembedded_pi) == -1)
throw std::runtime_error("Failed to add embedded_pi 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__"));
// Load the python file
std::string file = "YOUR_PYTHON_FILE.py";
try{python::exec_file(file.c_str(),global,global);
}catch(boost::python::error_already_set const &){
// Parse and output the exception
PyErr_Print();
}
// pull the python class from global
// This is the name of MyPythonClass
python::object LOT = global["LOT"];
// Now creating and using instances of the Python class is almost easy
python::object lot_base = LOT();
Base& lot = python::extract<Base&>(lot_base) BOOST_EXTRACT_WORKAROUND;
try{lot.func1();
}catch(boost::python::error_already_set const &){
PyErr_Print();
}
try{std::string hola = lot.func2("hello");
}catch(boost::python::error_already_set const &){
PyErr_Print();
}
Py_Finalize();
return 1;
}
假设我有一个 Python class 像这样:
class MyPythonClass:
def Func1(self, param):
return
def Func2(self, strParam):
return strParam
如果我想在我的 C++ 代码中嵌入包含 class 的 Python 脚本,请通过我的 C++ 代码创建该对象的实例,然后调用该 python 对象,我该怎么做?
我认为它会是这样的:
namespace python = boost::python;
python::object main = python::import("main");
python::object mainNamespace = main.attr("__dict__");
python::object script = python::exec_file(path_to_my_script, mainNamespace);
python::object foo = mainNamespace.attr("MyPythonClass")();
python::str func2return = foo.attr("Func2")("hola");
assert(func2return == "hola");
但是我尝试过此代码的许多变体都没有奏效。为了能够做到这一点,我需要在我的代码中加入什么神奇的调味料?
这就是最终对我有用的方法。
namespace python = boost::python;
python::object main = python::import("main");
python::object mainNamespace = main.attr("__dict__");
//add the contents of the script to the global namespace
python::object script = python::exec_file(path_to_my_script, mainNamespace);
//add an instance of the object to the global namespace
python::exec("foo = MyPythonClass()", mainNamespace);
//create boost::python::object that refers to the created object
python::object foo = main.attr("foo");
//call Func2 on the python::object via attr
//then extract the result into a const char* and assign it to a std::string
//the last bit could be done on multiple lines with more intermediate variables if desired
const std::string func2return = python::extract<const char*>(foo.attr("Func2")("hola"));
assert(func2return == "hola");
如果有更好的方法,欢迎留言评论。
下面是一个使用 Boost::python 嵌入的例子。我特别喜欢这种方法,因为使用 python class 函数就像在 python 中一样简单。但是,它确实需要一些设置。
#include <boost/python.hpp>
// An abstract base class
class Base : public boost::noncopyable
{
public:
virtual ~Base() {};
virtual void func1() = 0;
virtual std::string func2(std::string strParam) = 0;
}
// Boost.Python wrapper class for Base
// a function pointer to Base::hello and then calls function
struct BaseWrap : Base, python::wrapper<Base>
{
virtual void func1()
{
this->get_override("func1")();
}
virtual void func2(std::string strParam)
{
std::string str = this->get_override("func2")(strParam);
return str;
}
}
// Pack the Base class wrapper into a module
BOOST_PYTHON_MODULE(embedded_py)
{
//creating p c++ class instance called "base" and constructed with "Base"
python::class_<BaseWrap, boost::noncopyable> base("Base");
}
int main()
{
Py_Initialize();
std::cout << "registering extension module embedded_py ..." << std::endl;
// Register the module with the interpreter
if (PyImport_AppendInittab("embedded_pi", initembedded_pi) == -1)
throw std::runtime_error("Failed to add embedded_pi 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__"));
// Load the python file
std::string file = "YOUR_PYTHON_FILE.py";
try{python::exec_file(file.c_str(),global,global);
}catch(boost::python::error_already_set const &){
// Parse and output the exception
PyErr_Print();
}
// pull the python class from global
// This is the name of MyPythonClass
python::object LOT = global["LOT"];
// Now creating and using instances of the Python class is almost easy
python::object lot_base = LOT();
Base& lot = python::extract<Base&>(lot_base) BOOST_EXTRACT_WORKAROUND;
try{lot.func1();
}catch(boost::python::error_already_set const &){
PyErr_Print();
}
try{std::string hola = lot.func2("hello");
}catch(boost::python::error_already_set const &){
PyErr_Print();
}
Py_Finalize();
return 1;
}