注意到有人写了这样的枚举:
from enum import IntEnum
class Animal(IntEnum):
dog = 1,
cat = 2
我认为这是一个错误会导致运行时错误,因为狗的值实际上是一个元组。令我惊讶的是,它有效,Animal.dog.value == 1
。
这有效:
class Potato(IntEnum):
spud = ()
将空元组以某种方式转换为整数0(可能是参数splatting到int
的调用?)。
但这并不起作用:
class Potato(IntEnum):
spud = []
我们得到TypeError: int() argument must be a string or a number, not 'list'
。
我在python3和enum34 backport都看到了python 2。
如何/为什么IntEnum
或他的元类隐式将元组转换为整数?
答案 0 :(得分:3)
我必须调查enum.py
以了解会发生什么。实际上,当您输入的值不是元组时,它会转换为(value,)
,如果是元组则保持不变。然后,对于IntEnum
,使用int(*args)
计算实际值。
好的,现在发生了什么:
int(10) = 10
,一切都很好int([...])
会出错如果你给一个元组(string_value,base)示例('1f', 16)
:你正确得到31!
>>> class Animal(IntEnum):
dog = '1F', 16
cat = 5
>>> Animal.dog.value
31
但是我在模块文档中找不到它的任何痕迹,我认为它必须被视为一个实现细节......
答案 1 :(得分:1)
要支持__new__
和__init__
方法,您的值将转换为元组并作为参数传递给__init__
或__new__
方法以生成枚举值。为了支持多个参数,不转换任何现有元组。
在Allowed members and attributes of enumerations中声明:
注意:如果您的枚举定义了
__new__()
和/或__init__()
,那么给予枚举成员的任何值都将传递给这些方法。有关示例,请参阅Planet
。
如果定义了
__new__()
或__init__()
,则会将枚举成员的值传递给这些方法。
对于你的情况,会发生这种情况:
2
变为(2,)
1,
或()
保留元组。之后int.__new__
方法被称为int.__new__(*args)
。
现在发生了什么:
int(1,)
是1
。int(2,)
是2
。int()
是0
。您可以扩展它以支持任意基本整数:
>>> class BasesOfTenEnum(IntEnum):
... octal = '10', 8
... decimal = '10', 10
... hexadecimal = '10', 16
...
>>> list(BasesOfTenEnum)
[<BasesOfTenEnum.octal: 8>, <BasesOfTenEnum.decimal: 10>, <BasesOfTenEnum.hexadecimal: 16>]
作为一个有趣的旁注,为了使事情变得更复杂一点,如果将tuple
与Enum
混合,则元组值将包含在另一个元组中,因此您仍然可以将其传递给{ {1}}作为一个论点。