28

I'd like to generate some types at runtime from a config file. For simplity, let's assume I already have the data loaded as a python dictionary:

color_values = dict(RED = 1, YELLOW = 2, GREEN = 3)

How can I transform this into the type (using enum)

class Color(enum.Enum):
    RED = 1
    YELLOW = 2
    GREEN = 3

The following doesn't work

def make_enum(name, values):
    return type(name, (enum.Enum,), values)
>>> Color = make_enum('Color', color_values)
AttributeError: 'dict' object has no attribute '_member_names'
3
  • 1
    You should probably use an OrderedDict rather than a regular dict. Commented Nov 15, 2017 at 4:04
  • Relevant: stackoverflow.com/q/36932/1959808 Commented Nov 15, 2017 at 4:08
  • 1
    @IoannisFilippidis: In my defense, I remembered that question as being one pre-enum.Enum, which would just tell me to use it. Of course, you're right that it shows the example I needed there. Commented Nov 15, 2017 at 4:10

3 Answers 3

50
Color = Enum('Color', color_values)

Tada! There's a provided API for that. You can also give it an iterable of name-value pairs, or an iterable of just names (in which case the values will be auto-filled starting from 1), or a whitespace- or comma-separated string of names (which will also auto-fill values).

Sign up to request clarification or add additional context in comments.

Comments

1

Here's one super-hacky approach that seems to work:

def make_enum(name, values):
    _k = _v = None
    class TheEnum(enum.Enum):
        nonlocal _k, _v
        for _k, _v in values.items():
            locals()[_k] = _v
    TheEnum.__name__ = name
    return TheEnum

We have to use nonlocal there to stop Enum complaining about the keys k and v being duplicated.

Comments

-1

And another one that chooses to hit the metaclass internals instead:

def make_enum(name, values):
    meta = type(enum.Enum)
    bases = (enum.Enum,)
    dict = meta.__prepare__(name, bases)
    for k, v in values.items():
        dict[k] = v
    return meta(name, bases, dict)

Or with less __dunder__:

import types
def make_enum(name, values):
    def _update(d1, d2):
        for k, v in d2.items():
            d1[k] = v  # calls __setitem__
    return types.new_class(name, (enum.Enum,), None, lambda ns: _update(ns,values))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.