如何从值字典构造 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 抱怨键 kv 被重复。

还有一个选择命中元类内部:

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 开始自动填充),或一个以空格或逗号分隔的名称字符串(这也将自动填充值)。