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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.