简体   繁体   English

通过Boost.Python嵌入,Python 3无法将C ++类识别为模块

[英]C++ class not recognized by Python 3 as a module via Boost.Python Embedding

The following example from Boost.Python v1.56 shows how to embed the Python 3.4.2 interpreter into your own application. Boost.Python v1.56中的以下示例显示了如何将Python 3.4.2解释器嵌入到您自己的应用程序中。 Unfortunately that example does not work out of the box on my configuration with MSVC2013 under Windows 8.1. 不幸的是,在Windows 8.1下使用MSVC2013进行配置时,该示例无法正常使用。 And I have not found 1 working complete example about embedding, at least none that is younger than 10 years or so. 我还没有找到一个关于嵌入的完整示例,至少没有一个比10年左右更年轻。

I receive the following error running it: ImportError: 'embedded_hello' is not a built-in module 运行它时收到以下错误: ImportError:'embedded_hello'不是内置模块

The code is here: http://pastebin.com/shTtdxT8 代码在这里: http//pastebin.com/shTtdxT8

Any hints what I can do to let this run? 任何暗示我可以做什么让这个运行? And in general how to expose a c++ class in Python and vice versa? 一般来说如何在Python中公开c ++类,反之亦然?

The code is compiling with a Python 2 header configuration. 代码正在使用Python 2头配置进行编译。 When compiling with a Python 3 header configuration, the boost/python/module_init.hpp would have declared the embedded_hello module's initialization function as PyInit_embedded_hello rather than initembedded_hello . 使用Python 3头配置进行编译时, boost/python/module_init.hpp会将embedded_hello模块的初始化函数声明为PyInit_embedded_hello而不是initembedded_hello I highly recommend verifying the proper header configuration, and performing a clean build of Boost.Python, as Boost.Python and modules built with the library need to use the same header configuration. 我强烈建议验证正确的头配置,并执行Boost.Python的干净构建,因为Boost.Python和使用库构建的模块需要使用相同的头配置。

Additionally, when adding modules to the built-in table, the PyImport_AppendInittab() calls need to occur before Py_Initialize() . 此外,在将模块添加到内置表时, PyImport_AppendInittab()调用需要在Py_Initialize()之前Py_Initialize() The PyImport_AppendInittab() documentation explicitly states: PyImport_AppendInittab()文档明确指出:

Add a single module to the existing table of built-in modules. 将单个模块添加到现有内置模块表中。 ... This should be called before Py_Initialize() . ...这应该在Py_Initialize()之前Py_Initialize()

Boost.Python uses the BOOST_PYTHON_MODULE macro to define a Python module. Boost.Python使用BOOST_PYTHON_MODULE宏来定义Python模块。 Within the body of the module, the current scope is the module itself. 在模块的主体内,当前范围是模块本身。 Thus, when C++ types are exposed via type wrappers, such as when a C++ classes is exposed to Python via boost::python::class_ , the resulting Python class will be within the module defined by BOOST_PYTHON_MODULE . 因此,当通过类型包装器公开C ++类型时,例如当通过boost::python::class_将C ++类暴露给Python时,生成的Python类将位于BOOST_PYTHON_MODULE定义的模块中。

On the other hand, user-defined types declared in Python are first-class objects. 另一方面,在Python中声明的用户定义类型是第一类对象。 From a C++ perspective, they can be treated as though they are a factory function. 从C ++的角度来看,它们可以被视为工厂函数。 Hence, to use a Python defined class in C++, one needs to get a handle to the class object, then instantiate an instance of a class by calling the class object. 因此,要在C ++中使用Python定义的类,需要获取类对象的句柄,然后通过调用类对象来实例化类的实例。


Here is a complete minimal example demonstrating embedding a Python 3 interpreter that: 这是一个完整的最小示例,演示了如何嵌入Python 3解释器:

  • Imports a module ( example ) that has been built directly into the binary and exposes a basic C++ class ( spam_wrap ) to Python ( example.Spam ) that has virtual function/dispatching with a default. 导入直接构建到二进制文件中的模块( example ),并将基本C ++类( spam_wrap )公开给具有默认的虚函数/调度的Python( example.Spam )。
  • Demonstrates using the exposed Python class ( example.Spam ). 演示使用公开的Python类( example.Spam )。
  • Derives from the exposed Python class ( example.Spam ) within Python ( example.PySpam ) and uses the resulting class. 从Python( example.Spam )中公开的Python类( example.Spamexample.PySpam并使用生成的类。
#include <iostream>
#include <boost/python.hpp>

/// @brief Mockup Spam model.
struct spam
  : boost::noncopyable
{
  virtual ~spam() {};
  virtual std::string hello() { return "Hello from C++"; }
};

//@ brief Mockup Spam wrapper.
struct spam_wrap
  : spam,
    boost::python::wrapper<spam>
{
  virtual std::string hello()
  {
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
    return boost::python::call<std::string>(
      this->get_override("hello").ptr());
#else
    return this->get_override("hello")();
#endif
  }

  std::string default_hello() { return this->spam::hello(); }
};

/// @brief Python example module.
BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;

  // Expose C++ spam_wrap as Python Spam class.
  python::class_<spam_wrap, boost::noncopyable>("Spam")
    .def("hello", &spam::hello, &spam_wrap::default_hello)
    ;
}   

int main()
{
  // Add example to built-in.
  PyImport_AppendInittab("example", &PyInit_example);

  // Start the interpreter.
  Py_Initialize();

  namespace python = boost::python;
  try
  {
    python::object main = python::import("__main__");
    python::object global = main.attr("__dict__");

    // Execute Python code, using the example module.
    exec(
      "from example import Spam          \n"
      "spam = Spam()                     \n"
      "                                  \n"
      "class PySpam(Spam):               \n"
      "    def hello(self):              \n"
      "        return 'Hello from Python'\n",     
      global, global);

    /// Check the instance of the Python object using the C++ class.
    // >>> spam_object = spam
    python::object spam_object = global["spam"];
    assert(python::extract<spam>(spam_object).check());
    // >>> result = spam_object.hello()
    python::object result = spam_object.attr("hello")();
    // >>> print(result)
    std::cout << python::extract<std::string>(result)() << std::endl;
    // >>> assert("Hello from C++" == result)
    assert("Hello from C++" == python::extract<std::string>(result)());

    /// Create an instance using PySpam class.  It too is a Python object.
    // >>> py_spam_type = PySpam
    python::object py_spam_type = global["PySpam"];
    // >>> py_spam_object = py_spam_type()
    python::object py_spam_object = py_spam_type();
    // >>> result = py_spam_object()
    result = py_spam_object.attr("hello")();
    // >>> print(result)
    std::cout << python::extract<std::string>(result)() << std::endl;
    // >>> assert("Hello from Python" == result)
    assert("Hello from Python" == python::extract<std::string>(result)());
  }
  catch (const python::error_already_set&)
  {
    PyErr_Print();
  }
}

The program should run to completion without errors, resulting in the following output: 该程序应该运行完成而不会出现错误,从而产生以下输出:

Hello from C++
Hello from Python

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM