如何在Python中表示'Enum'?
我主要是做C#开发的,但现在正在做一个Python的项目。
在Python中,我怎么能表示一个类似于枚举(Enum)的东西呢?
43 个回答
356
这里有一个实现的例子:
class Enum(set):
def __getattr__(self, name):
if name in self:
return name
raise AttributeError
这是它的使用方法:
Animals = Enum(["DOG", "CAT", "HORSE"])
print(Animals.DOG)
977
在PEP 435之前,Python没有类似的功能,但你可以自己实现一个。
我个人喜欢简单的方式(我在网上见过一些复杂得令人头疼的例子),像这样……
class Animal:
DOG = 1
CAT = 2
x = Animal.DOG
在Python 3.4中(PEP 435),你可以让Enum成为基类。这样你就能获得一些额外的功能,具体内容可以在PEP中找到。例如,枚举成员和整数是不同的,它们由一个name
和一个value
组成。
from enum import Enum
class Animal(Enum):
DOG = 1
CAT = 2
print(Animal.DOG)
# <Animal.DOG: 1>
print(Animal.DOG.value)
# 1
print(Animal.DOG.name)
# "DOG"
如果你不想手动输入值,可以使用以下快捷方式:
class Animal(Enum):
DOG, CAT = range(2)
Enum
的实现可以转换为列表,并且是可迭代的。它的成员顺序是根据声明的顺序,而与它们的值无关。例如:
class Animal(Enum):
DOG = 1
CAT = 2
COW = 0
list(Animal)
# [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.COW: 0>]
[animal.value for animal in Animal]
# [1, 2, 0]
Animal.CAT in Animal
# True
2990
枚举(Enums)是在Python 3.4中新增的功能,具体内容可以参考PEP 435。此外,它也被移植到了3.3、3.2、3.1、2.7、2.6、2.5和2.4版本上。
如果你想尝试更高级的枚举技巧,可以使用aenum库(适用于2.7和3.3以上版本,和enum34
是同一个作者)。不过,Python 2和Python 3之间的代码并不是完全兼容,比如在Python 2中,你需要使用__order__
。
- 要使用
enum34
,可以运行$ pip install enum34
- 要使用
aenum
,可以运行$ pip install aenum
安装enum
(没有数字的那个)会安装一个完全不同且不兼容的版本。
from enum import Enum # for enum34, or the stdlib version
# from aenum import Enum # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')
Animal.ant # returns <Animal.ant: 1>
Animal['ant'] # returns <Animal.ant: 1> (string lookup)
Animal.ant.name # returns 'ant' (inverse lookup)
或者可以这样写:
class Animal(Enum):
ant = 1
bee = 2
cat = 3
dog = 4
在早期版本中,实现枚举的一种方法是:
def enum(**enums):
return type('Enum', (), enums)
使用方法如下:
>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'
你也可以很容易地支持自动枚举,像这样:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
return type('Enum', (), enums)
使用方法如下:
>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1
可以通过这种方式支持将值转换回名称:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
enums['reverse_mapping'] = reverse
return type('Enum', (), enums)
这会覆盖任何同名的内容,但在输出枚举时非常有用。如果反向映射不存在,它会抛出一个KeyError
错误。在第一个例子中:
>>> Numbers.reverse_mapping['three']
'THREE'
如果你在使用MyPy,另一种表示“枚举”的方式是使用typing.Literal
。
例如:
from typing import Literal #python >=3.8
from typing_extensions import Literal #python 2.7, 3.4-3.7
Animal = Literal['ant', 'bee', 'cat', 'dog']
def hello_animal(animal: Animal):
print(f"hello {animal}")
hello_animal('rock') # error
hello_animal('bee') # passes