Reputation: 97555
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'
Upvotes: 26
Views: 31956
Reputation: 97555
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))
Upvotes: -1
Reputation: 280182
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).
Upvotes: 47
Reputation: 97555
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.
Upvotes: 1