在Python中将枚举转换为整数

67

我有一个枚举类型 Nationality:

class Nationality:
        Poland='PL'
        Germany='DE'
        France='FR'

我该如何以这种或类似的方式将此枚举转换为整数:

position_of_enum = int(Nationality.Poland)  # here I want to get 0

我知道如果我有代码的话就可以做到:

counter=0
for member in dir(Nationality):
    if getattr(Nationality, member) == code:
        lookFor = member
        counter += 1
return counter

但是我没有,而且这种方式对于Python来说看起来太复杂了。我相信有更简单的方法。


一个类不是枚举类型,因此你不能进行比较。 - Bite code
11个回答

136
请使用 IntEnum
from enum import IntEnum

class loggertype(IntEnum):
    Info = 0
    Warning = 1
    Error = 2
    Fatal = 3

int(loggertype.Info)
0

4
请解释你的答案。 - Paulie
4
从Python 3.4版本开始,以下是“更正确”的答案(或者说,由库的创建者Ethan Furman提供的答案)。 - ac3d912
在上面的例子中,您还可以导入auto,然后将Warning、Error和Fatal初始化为auto()。 - learning2learn

38
使用enum34后向兼容aenum1,您可以创建一个专用的枚举类型
# using enum34
from enum import Enum

class Nationality(Enum):

    PL = 0, 'Poland'
    DE = 1, 'Germany'
    FR = 2, 'France'

    def __new__(cls, value, name):
        member = object.__new__(cls)
        member._value_ = value
        member.fullname = name
        return member

    def __int__(self):
        return self.value

并且在使用中:

>>> print(Nationality.PL)
Nationality.PL
>>> print(int(Nationality.PL))
0
>>> print(Nationality.PL.fullname)
'Poland'

上面的内容可以更轻松地使用aenum1编写:
# using aenum
from aenum import Enum, MultiValue

class Nationality(Enum):
    _init_ = 'value fullname'
    _settings_ = MultiValue

    PL = 0, 'Poland'
    DE = 1, 'Germany'
    FR = 2, 'France'

    def __int__(self):
        return self.value

具有以下额外功能:

>>> Nationality('Poland')
<Nationality.PL: 0>

1声明:我是Python标准库Enumenum34回溯高级枚举(aenum)库的作者。


非常好,非常感谢! - Regis May

13

有更好(并且更符合Python风格)的方法来实现你想要的功能。

可以使用元组(如果不需要修改可以使用列表),这样顺序就会被保留:

code_lookup = ('PL', 'DE', 'FR')
return code_lookup.index('PL') 

或者使用类似以下字典的方法:

code_lookup = {'PL':0, 'FR':2, 'DE':3}
return code_lookup['PL']  
后者更好,因为它更易读且更明确。
在您的特定情况下,namedtuple 也可能很有用,尽管这可能过于复杂。
import collections
Nationalities = collections.namedtuple('Nationalities', 
                                       ['Poland', 'France', 'Germany'])
nat = Nationalities('PL', 'FR', 'DE')
print nat.Poland
print nat.index(nat.Germany)

你缺少国籍名称。我必须要它们。 - user278618
@user278618 - 为了简洁起见,我将它们省略了。我的想法是你可以在Nationality类中的某个地方使用查找表。你也可以轻松地替换成你的类属性,而不是字符串。 - Joe Kington

13
from enum import Enum

class Phone(Enum):
    APPLE = 1 #do not write comma (,)
    ANDROID = 2

#as int:
Phone.APPLE.value

如果使用逗号,则需要通过索引访问元组:

class Phone(Enum):
    APPLE = 1, # note: there is comma (,)
    ANDROID = 2,

#as int:
Phone.APPLE.value[0]
   

7
为什么不直接将值定义为数字,而不是字符串:
class Nationality:
    POLAND = 0
    GERMANY = 1
    FRANCE = 2

如果您需要访问两个字母的名称,可以提供一个映射表。 (或者反过来映射的字典等)

不要这样做,因为你可以在定义后随意更改它而不进行任何合理性检查:Nationality.GERMANY = 0。这在枚举中是行不通的,它是WORM(https://en.wikipedia.org/wiki/Write_once_read_many)。字典也是一样。枚举是正确的选择。 :) - Michael Dorner
不要这样做,因为你可以在定义后更改它,而没有任何合理性检查:Nationality.GERMANY = 0。这在枚举中不起作用,它是WORM(https://en.wikipedia.org/wiki/Write_once_read_many)。字典也是如此。枚举是正确的选择。 :) - Michael Dorner

5
你无法做到。Python不会存储类元素的顺序,dir()会以任意顺序返回它们。
从你的评论中可以看出,你确实需要一个从字符串到整数的映射,那么你应该按照这个要求去做:
code_lookup = {
    'PL': ("Poland", 0), 
    'DE': ("Germany", 1), 
    'FR': ("France", 2), 
    ... 
}

我正在使用这个枚举来设置选择器的值,该选择器在几个站点上具有不同的CSS和语言,并且每个站点上只有值属性是相同的。从这个选择器中,我必须选择国籍,选项的值为0,1,2。我在C#中使用了这种类型转换,所以这就是我得到这个想法的来源。 - user278618

5

实现这一目标的一个简单方法是:

from enum import Enum

class Nationality(Enum):
    Poland= 1, 'PL'
    Germany= 2, 'DE'
    France= 3, 'FR'

    def __int__(self):
        return self.value[0]

    def __str__(self):
        return self.value[1]

# Example use
if __name__ == "__main__":
    print(int(Nationality.Poland))
    print(Nationality.Poland)
    print(int(Nationality.Poland) == 1)

输出:

>>> 1
>>> PL
>>> True

解释:您可以按照所需的枚举和字符串表示方式创建自己的枚举,并通过覆盖相应的 __int__ __str__ 方法来获得所需的功能。据我所知,这不会违反枚举的任何合同,我更喜欢将功能封装在其各自的类中。


4

我见过类似这样的东西:

PL, FR, DE = range(3)

将其包装在一个类中,巧妙地,你就有了枚举的命名空间。


3
from enum import Enum

class Nationality(Enum):
    Poland = 'PL'
    Germany = 'DE'
    France = 'FR'

    @classmethod
    def get_index(cls, type):
        return list(cls).index(type)

然后:

Nationality.get_index(Nationality.Poland)
0

0
class Nationality(Enum):
    Poland = 'PL'
    Germany = 'DE'
    France = 'FR'

    @property
    def ordinal(self):
        return list(self.__class__).index(self)

    @classmethod
    def get(cls, index):
        return list(cls)[index]


然后:
>>> Nationality.Poland.ordinal
0

同样

>>> Nationality.get(2)
Nationality.France

1
请不要仅仅发布代码作为答案,还要提供解释您的代码是如何解决问题的。带有解释的答案通常更有帮助和更高质量,并且更有可能吸引赞同。 - rachwa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接