【问题标题】:How to define a mapping of enum members in the enum type?如何定义枚举类型中枚举成员的映射?
【发布时间】:2016-09-08 02:13:49
【问题描述】:

我有一个这样的 Python 枚举:

from enum import Enum, unique

@unique
class Levels(Enum):
  Unknown = 0
  Warning = 1
  Error =   2

  def __eq__(self, other):    return self.value ==  other.value
  def __ne__(self, other):    return self.value !=  other.value
  def __lt__(self, other):    return self.value <   other.value
  def __le__(self, other):    return self.value <=  other.value
  def __gt__(self, other):    return self.value >   other.value
  def __ge__(self, other):    return self.value >=  other.value

  __MAPPING__ = {
    "warn":   Warning,
    "error":  Error
  }

  @classmethod
  def Parse(cls, value, default=None):
    return cls.__MAPPING__.get(value, default)

在这个例子中,我已经将映射提取到一个类成员中(根据timeit.timeit(),它更快)。

我现在的问题是,dict 值使用原始枚举成员值(整数)而不是创建的枚举成员(EnumMeta)。这是合理的,因为在构造 dict 时不存在。

我如何/在哪里可以挂钩到 Enum 类/EnumMeta 类或我自己的 Levels 类,以使用创建的枚举成员修补字典?

【问题讨论】:

    标签: python-3.x enums metaclass


    【解决方案1】:

    [仅显示相关部分...]

    @unique
    class Levels(Enum):
        Unknown = 0
        Warning = 1
        Error =   2
    
        __MAPPING__ = {
            "warn":   Warning,
            "error":  Error
       }
    
        def __init__(self, *args):
            """Patch the embedded MAP dictionary"""
            self.__class__.__MAPPING__[self._name_] = self
    

    __init__ 在创建后为每个成员调用,因此此时您可以使用成员名称作为键更新__MAPPING__。如果你经常使用这种模式,你应该考虑使用另一个装饰器:

    def add_mapping(enum_cls):
        for name in enum_cls.__MAPPING__:
            member = enum_cls.__members__[name]
            enum_cls.__MAPPING__[name] = member
        return enum_cls
    

    并在使用中:

    @add_mapping
    @unique
    class Levels(Enum):
        Unknown = 0
        Warning = ...
    

    【讨论】:

    • 我稍微改进了你的解决方案,因为预期的枚举成员是字典中的值。因此,每个 init 调用都会扫描 dict 并用枚举成员替换一个值 (int)(如果在映射中定义)。
    • @Paebbels:啊,我误解了那部分。简化了您的代码并更新了装饰器。
    • @Paebbels:如果这只是性能提升,为什么不让所有成员都加入?此外,在 3.5 中,大部分(如果不是全部)性能影响已被移除。
    • @martineau:啊,OP有额外的P错字,我只成功地复制了一次错字。
    • @martineau:正确,_name_ 不是参数,在调用 __init__ 时它已经是成员的一部分。 (因此领先self. ;-))。它由元类设置。
    【解决方案2】:

    Mr. Furman's 提供above 为基础,使用map_value(name) 方法来获取映射:

    add_mapping(enum_cls): 
        enum_cls.__MAPPING__ = {e.value: e for e in enum_cls}
        enum_cls.map_value = lambda name, default=None: enum_cls.__MAPPING__.get(name, default)
        return enum_cls 
    

    【讨论】:

    • 我批准了您对我的回答的编辑,感谢您接受。现在,如果我们可以让编辑人员不要拒绝对他们不理解的代码进行错误修复。 :(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    相关资源
    最近更新 更多