如何从值字典构造 enum.Enum ?
How can I construct an enum.Enum from a dictionary of values?
我想在运行时从配置文件生成一些类型。为简单起见,假设我已经将数据加载为 python 字典:
color_values = dict(RED = 1, YELLOW = 2, GREEN = 3)
如何将其转换为类型(使用 enum
)
class Color(enum.Enum):
RED = 1
YELLOW = 2
GREEN = 3
以下无效
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'
这是一种似乎有效的超级 hacky 方法:
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
我们必须在那里使用 nonlocal
来阻止 Enum
抱怨键 k
和 v
被重复。
还有一个选择命中元类内部:
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)
或更少 __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))
Color = Enum('Color', color_values)
Tada! 为此提供了 API。您还可以给它一个可迭代的名称-值对,或一个仅包含名称的可迭代(在这种情况下,值将从 1 开始自动填充),或一个以空格或逗号分隔的名称字符串(这也将自动填充值)。
我想在运行时从配置文件生成一些类型。为简单起见,假设我已经将数据加载为 python 字典:
color_values = dict(RED = 1, YELLOW = 2, GREEN = 3)
如何将其转换为类型(使用 enum
)
class Color(enum.Enum):
RED = 1
YELLOW = 2
GREEN = 3
以下无效
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'
这是一种似乎有效的超级 hacky 方法:
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
我们必须在那里使用 nonlocal
来阻止 Enum
抱怨键 k
和 v
被重复。
还有一个选择命中元类内部:
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)
或更少 __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))
Color = Enum('Color', color_values)
Tada! 为此提供了 API。您还可以给它一个可迭代的名称-值对,或一个仅包含名称的可迭代(在这种情况下,值将从 1 开始自动填充),或一个以空格或逗号分隔的名称字符串(这也将自动填充值)。