5

我在使用 Boost-Python 为 Python 包装枚举时遇到问题。

最初,我打算在try-catch(我在下面插入了整个代码)语句中执行以下操作:

main_namespace["Motion"] = enum_<TestClass::Motion>("Motion")
    .value("walk", TestClass::walk)
    .value("bike", TestClass::bike)
;

一切都很好,编译完成了。在运行时我收到了这个错误(这对我来说毫无意义):

AttributeError: 'NoneType' object has no attribute 'Motion'

之后我决定在我的代码中使用 BOOST_PYTHON_MODULE 编写一个 Python 模块。初始化 Python 解释器后,我想立即使用这个模块,但不知道如何(?)。以下是我的整个代码:

#include <boost/python.hpp>
#include <iostream>

using namespace std;
using namespace boost::python;

BOOST_PYTHON_MODULE(test)
{
    enum_<TestClass::Motion>("Motion")
        .value("walk", TestClass::walk)
        .value("bike", TestClass::bike)
    ;
}

int main()
{
    Py_Initialize();

    try
    {    
        object pyMainModule = import("__main__");
        object main_namespace = pyMainModule.attr("__dict__");

        //What previously I intended to do
        //main_namespace["Motion"] = enum_<TestClass::Motion>("Motion")
        //  .value("walk", TestClass::walk)
        //  .value("bike", TestClass::bike)
        //;

        //I want to use my enum here
        //I need something like line below which makes me able to use the enum!

        exec("print 'hello world'", main_namespace, main_namespace);
    }
    catch(error_already_set const&)
    {
        PyErr_Print();
    }

    Py_Finalize();
    return 0;
}

任何有关在 Python 中包装和使用枚举的有用信息都将不胜感激!提前致谢

4

1 回答 1

8

AttributeError是在没有首先设置范围的情况下尝试创建 Python 扩展类型的结果。构造boost::python::enum_函数声明:

构造一个enum_对象,该对象包含一个派生自int名为的 Python 扩展类型name。当前作用域的named 属性绑定到新的扩展类型。

嵌入 Python 时,要使用自定义 Python 模块,通常最容易使用PyImport_AppendInittab,然后按名称导入模块。

PyImport_AppendInittab("example", &initexample);
...
boost::python::object example = boost::python::import("example");

这是一个完整的示例,显示了通过 Boost.Python 公开的两个枚举。一个包含在example由 导入的单独模块 () 中,main另一个直接暴露在main.

#include <iostream>
#include <boost/python.hpp>

/// @brief Mockup class with a nested enum.
struct TestClass
{
  /// @brief Mocked enum.
  enum Motion
  {
    walk,
    bike 
  };

  // @brief Mocked enum.
  enum Color
  {
    red,
    blue
  };
};

/// @brief Python example module.
BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::enum_<TestClass::Motion>("Motion")
    .value("walk", TestClass::walk)
    .value("bike", TestClass::bike)
    ;
}   

int main()
{
  PyImport_AppendInittab("example", &initexample); // Add example to built-in.
  Py_Initialize(); // Start interpreter.

  // Create the __main__ module.
  namespace python = boost::python;

  try
  {
    python::object main = python::import("__main__");
    python::object main_namespace = main.attr("__dict__");
    python::scope scope(main); // Force main scope

    // Expose TestClass::Color as Color
    python::enum_<TestClass::Color>("Color")
      .value("red", TestClass::red)
      .value("blue", TestClass::blue)
      ;

    // Print values of Color enumeration.
    python::exec(
      "print Color.values",
      main_namespace, main_namespace);

    // Get a handle to the Color enumeration.
    python::object color = main_namespace["Color"];
    python::object blue  = color.attr("blue");

    if (TestClass::blue == python::extract<TestClass::Color>(blue))
      std::cout << "blue enum values matched." << std::endl;

    // Import example module into main namespace.
    main_namespace["example"] = python::import("example");

    // Print the values of the Motion enumeration.
    python::exec(
      "print example.Motion.values",
      main_namespace, main_namespace);

    // Check if the Python enums match the C++ enum values.
    if (TestClass::bike == python::extract<TestClass::Motion>(
          main_namespace["example"].attr("Motion").attr("bike")))
      std::cout << "bike enum values matched." << std::endl;
  }
  catch (const python::error_already_set&)
  {
    PyErr_Print();
  }
}

输出:

{0: __main__.Color.red, 1: __main__.Color.blue}
blue enum values matched.
{0: example.Motion.walk, 1: example.Motion.bike}
bike enum values matched.
于 2013-09-24T21:32:38.540 回答