【问题标题】:How to Create and Use Instance of a Python Object with boost::python如何使用 boost::python 创建和使用 Python 对象的实例
【发布时间】:2017-02-10 03:06:50
【问题描述】:

假设我有一个这样的 Python 类:

class MyPythonClass:
    def Func1(self, param):
        return
    def Func2(self, strParam):
        return strParam

如果我想在我的 C++ 代码中嵌入包含该类的 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");

但是我尝试过的这段代码的许多变体都没有奏效。为了能够做到这一点,我需要将什么魔法酱倒在我的代码上?

【问题讨论】:

    标签: c++ boost boost-python


    【解决方案1】:

    这最终对我有用。

    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");
    

    如果有更好的方法,请随时发表评论。

    【讨论】:

    • 这对我来说真的不起作用(使用 Python 3.6,所以只使用新样式的类)。也就是说,this 工作得很好。
    • 感谢分享!是的,我可能应该用一个新的答案来更新这个问题,因为我已经发现了更好的方法。该博客很好地将整个过程封装在一个地方。
    【解决方案2】:

    以下是使用 Boost::python 嵌入的示例。我特别喜欢这种方法,因为使用 python 类函数就像在 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;
    }
    

    【讨论】:

    • 我刚刚注意到 Adam Palunuik 在上面发表了类似的建议。
    猜你喜欢
    • 2020-10-10
    • 2012-07-21
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多