我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
当前回答
我非常喜欢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'
其他回答
在答案列表中没有看到这个,这是我想出的一个。它允许使用'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!
来自PyPI的枚举包提供了枚举的健壮实现。之前的回答提到了PEP 354;这一提议遭到拒绝,但该提议得到了执行 http://pypi.python.org/pypi/enum。
用法简单而优雅:
>>> from enum import Enum
>>> Colors = Enum('red', 'blue', 'green')
>>> shirt_color = Colors.green
>>> shirt_color = Colors[2]
>>> shirt_color > Colors.red
True
>>> shirt_color.index
2
>>> str(shirt_color)
'green'
这是我在这里找到的一个很好的Python食谱:http://code.activestate.com/recipes/577024-yet-another-enum-for-python/
def enum(typename, field_names):
"Create a new enumeration type"
if isinstance(field_names, str):
field_names = field_names.replace(',', ' ').split()
d = dict((reversed(nv) for nv in enumerate(field_names)), __slots__ = ())
return type(typename, (object,), d)()
使用示例:
STATE = enum('STATE', 'GET_QUIZ, GET_VERSE, TEACH')
更多细节可以在食谱页面上找到。
Alexandru对枚举使用类常量的建议效果很好。
我还喜欢为每组常量添加字典,以查找人类可读的字符串表示。
这有两个目的:a)它提供了一种简单的方法来漂亮地打印你的枚举;b)字典在逻辑上对常量进行分组,以便您可以测试成员关系。
class Animal:
TYPE_DOG = 1
TYPE_CAT = 2
type2str = {
TYPE_DOG: "dog",
TYPE_CAT: "cat"
}
def __init__(self, type_):
assert type_ in self.type2str.keys()
self._type = type_
def __repr__(self):
return "<%s type=%s>" % (
self.__class__.__name__, self.type2str[self._type].upper())
Alec Thomas简洁回答的一个变体(支持获取枚举值的名称):
class EnumBase(type):
def __init__(self, name, base, fields):
super(EnumBase, self).__init__(name, base, fields)
self.__mapping = dict((v, k) for k, v in fields.iteritems())
def __getitem__(self, val):
return self.__mapping[val]
def enum(*seq, **named):
enums = dict(zip(seq, range(len(seq))), **named)
return EnumBase('Enum', (), enums)
Numbers = enum(ONE=1, TWO=2, THREE='three')
print Numbers.TWO
print Numbers[Numbers.ONE]
print Numbers[2]
print Numbers['three']