我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
当前回答
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)
其他回答
如果你需要数值,这是最快的方法:
dog, cat, rabbit = range(3)
在Python 3中。X你也可以在最后添加一个星号占位符,它将吸收范围内所有剩余的值,以防你不介意浪费内存和无法计数:
dog, cat, rabbit, horse, *_ = range(100)
Python没有内置的enum,其他答案有实现自己的enum的想法(您可能也对Python烹饪书中的顶部版本感兴趣)。
然而,在C中调用枚举的情况下,我通常只使用简单的字符串:由于对象/属性的实现方式,(C)Python已经优化为使用短字符串工作得非常快,因此使用整数并没有任何性能上的好处。为了防止输入错误/无效值,可以在选定的位置插入检查。
ANIMALS = ['cat', 'dog', 'python']
def take_for_a_walk(animal):
assert animal in ANIMALS
...
(与使用类相比,一个缺点是您失去了自动完成的好处)
在答案列表中没有看到这个,这是我想出的一个。它允许使用'in'关键字和len()方法:
class EnumTypeError(TypeError):
pass
class Enum(object):
"""
Minics enum type from different languages
Usage:
Letters = Enum(list('abc'))
a = Letters.a
print(a in Letters) # True
print(54 in Letters) # False
"""
def __init__(self, enums):
if isinstance(enums, dict):
self.__dict__.update(enums)
elif isinstance(enums, list) or isinstance(enums, tuple):
self.__dict__.update(**dict((v,k) for k,v in enumerate(enums)))
else:
raise EnumTypeError
def __contains__(self, key):
return key in self.__dict__.values()
def __len__(self):
return len(self.__dict__.values())
if __name__ == '__main__':
print('Using a dictionary to create Enum:')
Letters = Enum(dict((v,k) for k,v in enumerate(list('abcde'))))
a = Letters.a
print('\tIs a in e?', a in Letters)
print('\tIs 54 in e?', 54 in Letters)
print('\tLength of Letters enum:', len(Letters))
print('\nUsing a list to create Enum:')
Letters = Enum(list('abcde'))
a = Letters.a
print('\tIs a in e?', a in Letters)
print('\tIs 54 in e?', 54 in Letters)
print('\tLength of Letters enum:', len(Letters))
try:
# make sure we raise an exception if we pass an invalid arg
Failure = Enum('This is a Failure')
print('Failure')
except EnumTypeError:
print('Success!')
输出:
Using a dictionary to create Enum:
Is a in e? True
Is 54 in e? False
Length of Letters enum: 5
Using a list to create Enum:
Is a in e? True
Is 54 in e? False
Length of Letters enum: 5
Success!
这是我见过的最好的一个:“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)
保持简单,使用旧的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