2013-09-21 2 views
2

J'ai un problème pour envelopper un Enum pour Python en utilisant Boost-Python.Envelopper les Enums avec Boost-Python

Dans un premier temps que je voulais faire quelque chose comme ce qui suit dans le try-catch (je l'ai inséré mon code ci-dessous l'ensemble) déclaration:

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

Tout allait bien et la compilation a été fait. Au moment de l'exécution, je suis arrivé cette erreur (ce qui n'a pas de sens pour moi):

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

Ensuite j'ai décidé d'écrire un module Python en utilisant BOOST_PYTHON_MODULE dans mon code. Après avoir initialisé l'interpréteur Python, je voulais utiliser ce module tout de suite, mais je ne savais pas comment (?). Ce qui suit est mon code tout:

#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; 
} 

quelque chose d'utile à savoir sur l'emballage et l'utilisation énumérations en Python sera apprécié! Merci d'avance

Répondre

3

Le AttributeError est le résultat de la tentative de création d'un type d'extension Python sans définir d'abord la portée. Les états de constructeur: boost::python::enum_

Constructs un objet enum_ tenant un type d'extension python dérivé de int qui est nommé name. L'attribut name d de la portée actuelle est lié au nouveau type d'extension.

Lors de l'intégration Python, d'utiliser un module Python personnalisé, il est souvent plus facile à utiliser PyImport_AppendInittab, puis importer le module par son nom.

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

Voici un exemple complet montrant deux énumérations exposés par Boost.Python. L'un est inclus dans un module distinct (example) qui est importé par main et l'autre directement dans 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(); 
    } 
} 

Sortie:

{0: __main__.Color.red, 1: __main__.Color.blue} 
blue enum values matched. 
{0: example.Motion.walk, 1: example.Motion.bike} 
bike enum values matched. 
+0

Votre démonstration adapter la réponse parfaite. Merci pour ça. Dans la ligne que vous avez forcée, la portée était une sorte d'astuce pour moi. Cela a résolu mon problème en réalité. Je voulais demander une brève explication sur les portées en python. En fait, je ne peux pas comprendre la différence entre une portée et un espace de noms. –

+1

@NOVIN: ['scope'] (http://www.boost.org/doc/libs/1_54_0/libs/python/doc/v2/scope.html#introduction) est une construction Boost.Python utilisée pour représenter le namespace qui contiendra des classes et des fonctions récemment enveloppées. Aussi, si vous avez trouvé la réponse bénéfique, vous pouvez considérer [upvoting ou accepting] (http://meta.stackoverflow.com/help/someone-answers). –