如果我使用元组,为什么IntEnum不关心?

时间:2014-09-30 15:43:10

标签: python enums

注意到有人写了这样的枚举:

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或他的元类隐式将元组转换为整数?

2 个答案:

答案 0 :(得分:3)

我必须调查enum.py以了解会发生什么。实际上,当您输入的值不是元组时,它会转换为(value,),如果是元组则保持不变。然后,对于IntEnum,使用int(*args)计算实际值。

好的,现在发生了什么:

  • 如果你给出一个简单的int:int(10) = 10,一切都很好
  • 如果你给一个包含单个int的元组:转换导致相同的情况
  • 如果您提供列表: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

Planet example

  

如果定义了__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>]

作为一个有趣的旁注,为了使事情变得更复杂一点,如果将tupleEnum混合,则元组值将包含在另一个元组中,因此您仍然可以将其传递给{ {1}}作为一个论点。