16

I have a c++ class with an enum inside, and I wanted to mimick that with boost::python, so that I can write MyClass.value in python. boost::python::class_ does not have an enum_ method, and I was looking for workarounds.

  1. I first tried with lambdas like

    MyClass{
        enum{value1,value2};
    };
    
    class_<MyClass>("MyClass").add_property("value1",&[](){return value1;}).staticmethod("value1");
    

    which gives compiler error (in get_signature for add_property). I know I could create getter method for each of the values, but that seems very awkward to me (typing-wise).

  2. Using attr:

    auto classObj=class_<MyClass>("MyClass");
    classObj.attr("value1")=(int)value1;
    classObj.attr("value2")=(int)value2;
    

    but it cannot be chained like .def and other methods returning reference to the instance.

Is there a more elegant solution?

Andrey Agibalov
  • 7,624
  • 8
  • 66
  • 111
eudoxos
  • 18,545
  • 10
  • 61
  • 110

1 Answers1

13

You can do it using a scope:

#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <boost/python/scope.hpp>
#include <boost/python/enum.hpp>

namespace bp = boost::python;

class MyClass{
    public:
        enum MyEnum {value1,value2};
};

BOOST_PYTHON_MODULE(nestedtest){

    bp::scope the_scope
        = bp::class_<MyClass>("MyClass")
        ;

    bp::enum_<MyClass::MyEnum>("MyEnum")
        .value("value1", MyClass::value1)
        .value("value2", MyClass::value2)
        .export_values()
        ;
}

Then in python, your enum values are:

In [8]: nestedtest.MyClass.MyEnum.values
Out[8]: {0: nestedtest.MyEnum.value1, 1: nestedtest.MyEnum.value2}

In [9]: nestedtest.MyClass.MyEnum.value1
Out[9]: nestedtest.MyEnum.value1

In [10]: nestedtest.MyClass.MyEnum.value2
Out[10]: nestedtest.MyEnum.value2

(from my ipython shell, I tested this and all ;)

James
  • 24,676
  • 13
  • 84
  • 130
  • 1
    The enum is nested, which is not what I want; it is obnoxious and less readable to type `.MyEnum` without some added value. – eudoxos Sep 04 '11 at 20:58
  • 3
    The added value is that if, say, your enum values were all `ThingyA` `ThingyB` `ThingyC`, then you expose them to python as `Thingy.A` `Thingy.B` `Thingy.C`. As the sort of obnoxious person that campaigns against namespace pollution and the associated global namespace ozone hole and all that, I value this feature ;) – James Sep 04 '11 at 21:19
  • 1
    That's a matter of opinion (which I don't agree with), in any case the question asks for `MyClass.value`. – eudoxos Sep 05 '11 at 05:44
  • 1
    You can get the behaviour you want by adding the following line for each enum value (assuming the same code as above). This will inject a new symbol into the "right" scope with the value you want. the_scope.attr("value1") = MyClass::value1; – tgoodhart Nov 10 '11 at 16:28