我试图对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函数中缺少某些内容,但是我无法弄清楚如何正确地实现我的预期。任何帮助表示赞赏。
谢谢。
最佳答案
首先,有一种更惯用且简单的方法来完成您似乎想做的事情:
class Abc(IntEnum):
A = 100
B = auto()
或者,无论如何您都将100和101作为注释,实时代码总是比注释更好:
class Abc(IntEnum):
A = 100
B = 101
您没有执行任何一项操作的事实向读者发出信号,表明您可能正在做一些更复杂的事情。据我所知,除了你不是,所以这是误导。
另外,您正在组合两种具有截然相反含义的模式:正如the docs所说,使用
()
习惯用法“向用户表示这些值并不重要”,但是使用IntEnum
显然意味着数值这些枚举常数不仅很重要,而且还很重要。不仅如此,用户还必须通读方法代码以找出那些重要的数值,而不是立即读取它们。
无论如何,如果您想使其正常工作,问题在于初始化后替换
_value_
并没有任何好处,实际上却没有。您要覆盖的是
__new__
,而不是the auto-numbering example in the docs中的__init__
。但是这里有两个区别(两者都与您使用
IntEnum
而不是Enum
的事实有关):您不能调用
object.__new__
,因为IntEnum
是int
,并且object.__new__
不能用于诸如int
之类的内置类型的实例。您可以通过查看cls
的mro动态地找到正确的基类,或者您也可以在此处硬编码int
。您不需要在这里进行中间基类的工作。 (当然,如果要创建多个自动编号的
IntEnum
,则可能仍需要一个。)所以:
class Abc(IntEnum):
def __new__(cls, n=100):
value = len(cls.__members__) + n
obj = int.__new__(cls, value)
obj._value_ = value
return obj
A = ()
B = ()
关于python - IntEnum子类比较不正确,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51486818/