我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
当前回答
我喜欢在Python中这样定义枚举:
class Animal:
class Dog: pass
class Cat: pass
x = Animal.Dog
这比使用整数更有漏洞,因为你不必担心确保整数是唯一的(例如,如果你说Dog = 1和Cat = 1,你就完蛋了)。
它比使用字符串更防bug,因为你不必担心拼写错误(例如。 x == "猫"无声失败,但x ==动物。Catt是一个运行时异常)。
附录: 你甚至可以通过让Dog和Cat继承一个具有正确元类的符号类来增强这个解决方案:
class SymbolClass(type):
def __repr__(self): return self.__qualname__
def __str__(self): return self.__name__
class Symbol(metaclass=SymbolClass): pass
class Animal:
class Dog(Symbol): pass
class Cat(Symbol): pass
然后,如果你使用这些值来索引一个字典,请求它的表示将使它们看起来很漂亮:
>>> mydict = {Animal.Dog: 'Wan Wan', Animal.Cat: 'Nyaa'}
>>> mydict
{Animal.Dog: 'Wan Wan', Animal.Cat: 'Nyaa'}
其他回答
Python 2.7和find_name()
下面是所选思想的一个易于阅读的实现,其中包含一些辅助方法,这些方法可能比“reverse_mapping”更python化,使用起来更简洁。要求Python >= 2.7。
为了解决下面的一些注释,枚举对于防止代码中的拼写错误非常有用,例如对于状态机,错误分类器等。
def Enum(*sequential, **named):
"""Generate a new enum type. Usage example:
ErrorClass = Enum('STOP','GO')
print ErrorClass.find_name(ErrorClass.STOP)
= "STOP"
print ErrorClass.find_val("STOP")
= 0
ErrorClass.FOO # Raises AttributeError
"""
enums = { v:k for k,v in enumerate(sequential) } if not named else named
@classmethod
def find_name(cls, val):
result = [ k for k,v in cls.__dict__.iteritems() if v == val ]
if not len(result):
raise ValueError("Value %s not found in Enum" % val)
return result[0]
@classmethod
def find_val(cls, n):
return getattr(cls, n)
enums['find_val'] = find_val
enums['find_name'] = find_name
return type('Enum', (), enums)
对于旧的Python 2.x
def enum(*sequential, **named):
enums = dict(zip(sequential, [object() for _ in range(len(sequential))]), **named)
return type('Enum', (), enums)
如果你命名它,是你的问题,但如果不创建对象而不是值允许你这样做:
>>> DOG = enum('BARK', 'WALK', 'SIT')
>>> CAT = enum('MEOW', 'WALK', 'SIT')
>>> DOG.WALK == CAT.WALK
False
当使用这里的其他实现时(在我的例子中使用命名实例时),必须确保永远不要尝试比较来自不同枚举的对象。这里有一个可能的陷阱:
>>> DOG = enum('BARK'=1, 'WALK'=2, 'SIT'=3)
>>> CAT = enum('WALK'=1, 'SIT'=2)
>>> pet1_state = DOG.BARK
>>> pet2_state = CAT.WALK
>>> pet1_state == pet2_state
True
呵!
Enum类可以是一行程序。
class Enum(tuple): __getattr__ = tuple.index
如何使用它(正向和反向查找、键、值、项等)
>>> State = Enum(['Unclaimed', 'Claimed'])
>>> State.Claimed
1
>>> State[1]
'Claimed'
>>> State
('Unclaimed', 'Claimed')
>>> range(len(State))
[0, 1]
>>> [(k, State[k]) for k in range(len(State))]
[(0, 'Unclaimed'), (1, 'Claimed')]
>>> [(k, getattr(State, k)) for k in State]
[('Unclaimed', 0), ('Claimed', 1)]
在PEP 435之前,Python没有等效的,但你可以实现自己的。
就我个人而言,我喜欢保持简单(我在网上看到过一些非常复杂的例子),就像这样……
class Animal:
DOG = 1
CAT = 2
x = Animal.DOG
在Python 3.4 (PEP 435)中,可以将Enum作为基类。这为您提供了一些额外的功能,详见PEP。例如,enum成员不同于整数,它们由名称和值组成。
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)
枚举实现可以转换为列表,并且是可迭代的。其成员的顺序是声明顺序,与它们的值无关。例如:
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
我喜欢在Python中这样定义枚举:
class Animal:
class Dog: pass
class Cat: pass
x = Animal.Dog
这比使用整数更有漏洞,因为你不必担心确保整数是唯一的(例如,如果你说Dog = 1和Cat = 1,你就完蛋了)。
它比使用字符串更防bug,因为你不必担心拼写错误(例如。 x == "猫"无声失败,但x ==动物。Catt是一个运行时异常)。
附录: 你甚至可以通过让Dog和Cat继承一个具有正确元类的符号类来增强这个解决方案:
class SymbolClass(type):
def __repr__(self): return self.__qualname__
def __str__(self): return self.__name__
class Symbol(metaclass=SymbolClass): pass
class Animal:
class Dog(Symbol): pass
class Cat(Symbol): pass
然后,如果你使用这些值来索引一个字典,请求它的表示将使它们看起来很漂亮:
>>> mydict = {Animal.Dog: 'Wan Wan', Animal.Cat: 'Nyaa'}
>>> mydict
{Animal.Dog: 'Wan Wan', Animal.Cat: 'Nyaa'}