我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
当前回答
在Java pre-JDK 5中使用的类型安全枚举模式有一个 优势的数量。就像Alexandru的回答一样,你创建了一个 类和类级别字段是枚举值;然而,枚举 值是类的实例,而不是小整数。这已经 优点是枚举值不会在不经意间比较相等 对于小整数,你可以控制它们的打印方式,任意添加 方法(如果有用的话),并使用isinstance进行断言:
class Animal:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def __repr__(self):
return "<Animal: %s>" % self
Animal.DOG = Animal("dog")
Animal.CAT = Animal("cat")
>>> x = Animal.DOG
>>> x
<Animal: dog>
>>> x == 1
False
python-dev上最近的一个线程指出,在野外有几个枚举库,包括:
flufl.enum lazr.enum ... 和富有想象力的enum
其他回答
这是我见过的最好的一个:“Python中的First Class Enums”
http://code.activestate.com/recipes/413486/
It gives you a class, and the class contains all the enums. The enums can be compared to each other, but don't have any particular value; you can't use them as an integer value. (I resisted this at first because I am used to C enums, which are integer values. But if you can't use it as an integer, you can't use it as an integer by mistake so overall I think it is a win.) Each enum is a unique value. You can print enums, you can iterate over them, you can test that an enum value is "in" the enum. It's pretty complete and slick.
编辑(cfi):上面的链接不兼容Python 3。下面是我将枚举.py移植到Python 3的端口:
def cmp(a,b):
if a < b: return -1
if b < a: return 1
return 0
def Enum(*names):
##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!
class EnumClass(object):
__slots__ = names
def __iter__(self): return iter(constants)
def __len__(self): return len(constants)
def __getitem__(self, i): return constants[i]
def __repr__(self): return 'Enum' + str(names)
def __str__(self): return 'enum ' + str(constants)
class EnumValue(object):
__slots__ = ('__value')
def __init__(self, value): self.__value = value
Value = property(lambda self: self.__value)
EnumType = property(lambda self: EnumType)
def __hash__(self): return hash(self.__value)
def __cmp__(self, other):
# C fans might want to remove the following assertion
# to make all enums comparable by ordinal value {;))
assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
return cmp(self.__value, other.__value)
def __lt__(self, other): return self.__cmp__(other) < 0
def __eq__(self, other): return self.__cmp__(other) == 0
def __invert__(self): return constants[maximum - self.__value]
def __nonzero__(self): return bool(self.__value)
def __repr__(self): return str(names[self.__value])
maximum = len(names) - 1
constants = [None] * len(names)
for i, each in enumerate(names):
val = EnumValue(i)
setattr(EnumClass, each, val)
constants[i] = val
constants = tuple(constants)
EnumType = EnumClass()
return EnumType
if __name__ == '__main__':
print( '\n*** Enum Demo ***')
print( '--- Days of week ---')
Days = Enum('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')
print( Days)
print( Days.Mo)
print( Days.Fr)
print( Days.Mo < Days.Fr)
print( list(Days))
for each in Days:
print( 'Day:', each)
print( '--- Yes/No ---')
Confirmation = Enum('No', 'Yes')
answer = Confirmation.No
print( 'Your answer is not', ~answer)
我非常喜欢Alec Thomas的解决方案(http://stackoverflow.com/a/1695250):
def enum(**enums):
'''simple constant "enums"'''
return type('Enum', (object,), enums)
它看起来优雅而简洁,但它只是一个创建具有指定属性的类的函数。
通过对函数进行一些修改,我们可以让它表现得更像“枚举”:
注意:我通过尝试重现 pygtk的新样式'enums'的行为(如gtk . messagtype . warning)
def enum_base(t, **enums):
'''enums with a base class'''
T = type('Enum', (t,), {})
for key,val in enums.items():
setattr(T, key, T(val))
return T
这将基于指定类型创建枚举。除了像前面的函数那样提供属性访问外,它的行为与您期望Enum对类型的行为一样。它还继承了基类。
例如,整数enum:
>>> Numbers = enum_base(int, ONE=1, TWO=2, THREE=3)
>>> Numbers.ONE
1
>>> x = Numbers.TWO
>>> 10 + x
12
>>> type(Numbers)
<type 'type'>
>>> type(Numbers.ONE)
<class 'Enum'>
>>> isinstance(x, Numbers)
True
用这个方法还可以做一件有趣的事情,那就是通过覆盖内置方法来定制特定的行为:
def enum_repr(t, **enums):
'''enums with a base class and repr() output'''
class Enum(t):
def __repr__(self):
return '<enum {0} of type Enum({1})>'.format(self._name, t.__name__)
for key,val in enums.items():
i = Enum(val)
i._name = key
setattr(Enum, key, i)
return Enum
>>> Numbers = enum_repr(int, ONE=1, TWO=2, THREE=3)
>>> repr(Numbers.ONE)
'<enum ONE of type Enum(int)>'
>>> str(Numbers.ONE)
'1'
所以,我同意。让我们不要在Python中强制执行类型安全,但我想保护自己不犯愚蠢的错误。我们怎么想呢?
class Animal(object):
values = ['Horse','Dog','Cat']
class __metaclass__(type):
def __getattr__(self, name):
return self.values.index(name)
它使我在定义枚举时避免了值冲突。
>>> Animal.Cat
2
还有一个方便的优势:非常快速的反向查找:
def name_of(self, i):
return self.values[i]
保持简单,使用旧的Python 2。x(参见下面的Python 3!):
class Enum(object):
def __init__(self, tupleList):
self.tupleList = tupleList
def __getattr__(self, name):
return self.tupleList.index(name)
然后:
DIRECTION = Enum(('UP', 'DOWN', 'LEFT', 'RIGHT'))
DIRECTION.DOWN
1
在使用Python 3时保持简单:
from enum import Enum
class MyEnum(Enum):
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4
然后:
MyEnum.DOWN
参见:https://docs.python.org/3/library/enum.html
Python的标准是PEP 435,所以在Python 3.4+中可以使用Enum类:
>>> from enum import Enum
>>> class Colors(Enum):
... red = 1
... green = 2
... blue = 3
>>> for color in Colors: print color
Colors.red
Colors.green
Colors.blue