【问题标题】:Wrapping Enums using Boost-Python使用 Boost-Python 封装枚举
【发布时间】:2013-09-21 08:59:43
【问题描述】:

我在使用 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 中封装和使用枚举的有用信息都将不胜感激! 提前致谢

【问题讨论】:

    标签: python boost boost-python


    【解决方案1】:

    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 公开的两个枚举。一个包含在由main 导入的单独模块(example)中,另一个直接暴露在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.
    

    【讨论】:

    • 您的演示非常适合答案。感谢那。在你强行使用范围对我来说是一种诡计。这实际上解决了我的问题。我想要求对python中的范围进行简要说明。实际上我无法理解范围和命名空间之间的区别。
    • @NOVIN:scope 是一个 Boost.Python 构造,用于表示将包含新包装的类和函数的命名空间。另外,如果您发现答案是有益的,您可以考虑upvoting or accepting它。
    猜你喜欢
    • 1970-01-01
    • 2012-05-31
    • 2014-05-24
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 2018-12-17
    • 2023-02-13
    • 2015-08-08
    相关资源
    最近更新 更多