IntEnum子类比较不正确

时间:2018-07-23 20:31:46

标签: python enums enumeration

我试图将IntEnum子类化,以将成员的值开始为某个值,然后自动为后续成员设置该值。这是我的课程:

class Abc(IntEnum):
  def __init__(self, n=100):
    super().__init__()
    self._value_ = n + len(self.__class__.__members__)

  A = () # 100
  B = () # 101

Abc.A == Abc.B # expects False, but gets True

如上所示,成员之间的比较不正确。当打印出Abc。 dict 时,我注意到_value2member_map_也不正确。

mappingproxy({'A': <Abc.A: 100>,
          'B': <Abc.B: 101>,
          '__doc__': 'An enumeration.',
          '__init__': <function __main__.Abc.__init__>,
          '__module__': '__main__',
          '__new__': <function enum.Enum.__new__>,
          '_generate_next_value_': <function enum.Enum._generate_next_value_>,
          '_member_map_': OrderedDict([('A', <Abc.A: 100>),
                       ('B', <Abc.B: 101>)]),
          '_member_names_': ['A', 'B'],
          '_member_type_': int,
          '_value2member_map_': {0: <Abc.B: 101>}})

请注意'_value2member_map_'如何具有键0而不是预期值100和101。我必须在init函数中缺少某些内容,但是我无法弄清楚如何正确地实现我的预期。任何帮助表示赞赏。 谢谢。

1 个答案:

答案 0 :(得分:3)

首先,还有一种更惯用且简单的方法来完成您似乎想做的事情:

class Abc(IntEnum):
    A = 100
    B = auto()

或者,考虑到您无论如何都将100和101作为注释,实时代码总是比注释更好:

class Abc(IntEnum):
    A = 100
    B = 101

您没有做 这两个事实,这向读者发出了一个信号,即您可能正在做一些更复杂的事情。据我所知,除了你不是,所以这是一种误导。

此外,您正在组合两种具有截然相反含义的模式:the docs说,使用()惯用法“向用户表示这些值并不重要”,而使用{{ 1}}显然意味着这些枚举常量的数值不仅很重要,而且还很重要。

不仅如此,用户还必须通读方法代码以找出那些重要的数值,而不是立即读取它们。


无论如何,如果您想使其正常工作,问题在于初始化后替换IntEnum并没有任何好处,实际上却没有。

您要覆盖的是_value_,而不是the auto-numbering example in the docs中的__new__

但是这里有两个区别(两者都与您使用__init__而不是IntEnum的事实有关)

  • 您不能调用Enum,因为object.__new__IntEnum,并且int不能用于诸如object.__new__之类的内置类型的实例。您可以通过浏览int的mro来动态地找出正确的基类,或者您也可以在此处硬编码cls
  • 您无需在这里进行中间基类的工作。 (当然,如果要创建多个自动编号的int,则可能仍需要一个。)

所以:

IntEnum