6

以下来自 Boost.Python v1.56 的示例展示了如何将 Python 3.4.2 解释器嵌入到您自己的应用程序中。不幸的是,该示例在我在 Windows 8.1 下使用 MSVC2013 的配置中无法开箱即用。而且我还没有找到 1 个关于嵌入的完整示例,至少没有一个小于 10 岁左右。

我在运行它时收到以下错误:ImportError: 'embedded_hello' is not a built-in module

代码在这里: http: //pastebin.com/shTtdxT8

任何提示我可以做些什么来让它运行?通常如何在 Python 中公开一个 c++ 类,反之亦然?

4

1 回答 1

11

该代码使用 Python 2 标头配置进行编译。当使用 Python 3 标头配置进行编译时,boost/python/module_init.hpp会将embedded_hello模块的初始化函数声明为PyInit_embedded_hello而不是initembedded_hello. 我强烈建议验证正确的头文件配置,并执行干净的 Boost.Python 构建,因为 Boost.Python 和使用该库构建的模块需要使用相同的头文件配置。

此外,在将模块添加到内置表时,PyImport_AppendInittab()调用需要发生在Py_Initialize(). 该PyImport_AppendInittab()文档明确指出:

将单个模块添加到现有的内置模块表中。...这应该在之前调用Py_Initialize()

Boost.Python 使用BOOST_PYTHON_MODULE宏来定义 Python 模块。在模块的主体内,当前范围是模块本身。因此,当 C++ 类型通过类型包装器公开时,例如当 C++ 类通过 公开给 Python 时boost::python::class_,生成的 Python 类将位于由BOOST_PYTHON_MODULE.

另一方面,在 Python 中声明的用户定义类型是一等对象。从 C++ 的角度来看,它们可以被视为工厂函数。因此,要在 C++ 中使用 Python 定义的类,需要获取类对象的句柄,然后通过调用类对象来实例化类的实例。


这是一个完整的最小示例,演示了嵌入 Python 3 解释器:

  • 导入一个example已直接构建到二进制文件中的模块 (),spam_wrap并向 Python ( example.Spam) 公开一个基本的 C++ 类 (),该类具有默认的虚函数/调度。
  • 演示使用公开的 Python 类 ( example.Spam)。
  • 从 Python ( ) 中公开的 Python 类 ( example.Spam)派生example.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();
  }
}

该程序应该运行完成而没有错误,产生以下输出:

Hello from C++
Hello from Python
于 2014-11-07T05:47:42.763 回答