如何定义枚举类型中枚举成员的映射?

Posted

技术标签:

【中文标题】如何定义枚举类型中枚举成员的映射?【英文标题】: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 类,以使用创建的枚举成员修补字典?

【问题讨论】:

【参考方案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 

【讨论】:

我批准了您对我的回答的编辑,感谢您接受。现在,如果我们可以让编辑人员不要拒绝对他们不理解的代码进行错误修复。 :(

以上是关于如何定义枚举类型中枚举成员的映射?的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript入门七:TypeScript的枚举

C++中类的一个数据成员是枚举类型,那么它在类中该怎么定义?

枚举类型的变量如何使用?

c语言枚举类型enum用法

Java中枚举类(enum)的简单使用

枚举映射附加约束的条件类型