我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
当前回答
这个解决方案是获取定义为列表的枚举类的简单方法(没有更多烦人的整数赋值):
enumeration.py:
import new
def create(class_name, names):
return new.classobj(
class_name, (object,), dict((y, x) for x, y in enumerate(names))
)
example.py:
import enumeration
Colors = enumeration.create('Colors', (
'red',
'orange',
'yellow',
'green',
'blue',
'violet',
))
其他回答
Davidg建议使用词典。我想更进一步,使用集合:
months = set('January', 'February', ..., 'December')
现在你可以测试一个值是否与集合中的一个值匹配,如下所示:
if m in months:
但是,像dF,我通常只使用字符串常量来代替枚举。
我使用元类来实现枚举(在我的想法中,它是一个const)。代码如下:
class ConstMeta(type):
'''
Metaclass for some class that store constants
'''
def __init__(cls, name, bases, dct):
'''
init class instance
'''
def static_attrs():
'''
@rtype: (static_attrs, static_val_set)
@return: Static attributes in dict format and static value set
'''
import types
attrs = {}
val_set = set()
#Maybe more
filter_names = set(['__doc__', '__init__', '__metaclass__', '__module__', '__main__'])
for key, value in dct.iteritems():
if type(value) != types.FunctionType and key not in filter_names:
if len(value) != 2:
raise NotImplementedError('not support for values that is not 2 elements!')
#Check value[0] duplication.
if value[0] not in val_set:
val_set.add(value[0])
else:
raise KeyError("%s 's key: %s is duplicated!" % (dict([(key, value)]), value[0]))
attrs[key] = value
return attrs, val_set
attrs, val_set = static_attrs()
#Set STATIC_ATTRS to class instance so that can reuse
setattr(cls, 'STATIC_ATTRS', attrs)
setattr(cls, 'static_val_set', val_set)
super(ConstMeta, cls).__init__(name, bases, dct)
def __getattribute__(cls, name):
'''
Rewrite the special function so as to get correct attribute value
'''
static_attrs = object.__getattribute__(cls, 'STATIC_ATTRS')
if name in static_attrs:
return static_attrs[name][0]
return object.__getattribute__(cls, name)
def static_values(cls):
'''
Put values in static attribute into a list, use the function to validate value.
@return: Set of values
'''
return cls.static_val_set
def __getitem__(cls, key):
'''
Rewrite to make syntax SomeConstClass[key] works, and return desc string of related static value.
@return: Desc string of related static value
'''
for k, v in cls.STATIC_ATTRS.iteritems():
if v[0] == key:
return v[1]
raise KeyError('Key: %s does not exists in %s !' % (str(key), repr(cls)))
class Const(object):
'''
Base class for constant class.
@usage:
Definition: (must inherit from Const class!
>>> class SomeConst(Const):
>>> STATUS_NAME_1 = (1, 'desc for the status1')
>>> STATUS_NAME_2 = (2, 'desc for the status2')
Invoke(base upper SomeConst class):
1) SomeConst.STATUS_NAME_1 returns 1
2) SomeConst[1] returns 'desc for the status1'
3) SomeConst.STATIC_ATTRS returns {'STATUS_NAME_1': (1, 'desc for the status1'), 'STATUS_NAME_2': (2, 'desc for the status2')}
4) SomeConst.static_values() returns set([1, 2])
Attention:
SomeCosnt's value 1, 2 can not be duplicated!
If WrongConst is like this, it will raise KeyError:
class WrongConst(Const):
STATUS_NAME_1 = (1, 'desc for the status1')
STATUS_NAME_2 = (1, 'desc for the status2')
'''
__metaclass__ = ConstMeta
##################################################################
#Const Base Class ends
##################################################################
def main():
class STATUS(Const):
ERROR = (-3, '??')
OK = (0, '??')
print STATUS.ERROR
print STATUS.static_values()
print STATUS.STATIC_ATTRS
#Usage sample:
user_input = 1
#Validate input:
print user_input in STATUS.static_values()
#Template render like:
print '<select>'
for key, value in STATUS.STATIC_ATTRS.items():
print '<option value="%s">%s</option>' % (value[0], value[1])
print '</select>'
if __name__ == '__main__':
main()
在2013-05-10,Guido同意将PEP 435纳入Python 3.4标准库。这意味着Python终于内置了对枚举的支持!
Python 3.3、3.2、3.1、2.7、2.6、2.5和2.4有一个可用的后端端口。它在Pypi上枚举34。
声明:
>>> from enum import Enum
>>> class Color(Enum):
... red = 1
... green = 2
... blue = 3
表示:
>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>
迭代:
>>> for color in Color:
... print(color)
...
Color.red
Color.green
Color.blue
编程访问:
>>> Color(1)
Color.red
>>> Color['blue']
Color.blue
有关更多信息,请参阅提案。官方文件可能很快就会发布。
为什么枚举必须是整数?不幸的是,在不改变Python语言的情况下,我想不出任何好看的构造来生成它,所以我将使用字符串:
class Enumerator(object):
def __init__(self, name):
self.name = name
def __eq__(self, other):
if self.name == other:
return True
return self is other
def __ne__(self, other):
if self.name != other:
return False
return self is other
def __repr__(self):
return 'Enumerator({0})'.format(self.name)
def __str__(self):
return self.name
class Enum(object):
def __init__(self, *enumerators):
for e in enumerators:
setattr(self, e, Enumerator(e))
def __getitem__(self, key):
return getattr(self, key)
也许现在更好的是,为了配置文件或其他远程输入,我们可以自然地对字符串进行测试。
例子:
class Cow(object):
State = Enum(
'standing',
'walking',
'eating',
'mooing',
'sleeping',
'dead',
'dying'
)
state = State.standing
In [1]: from enum import Enum
In [2]: c = Cow()
In [3]: c2 = Cow()
In [4]: c.state, c2.state
Out[4]: (Enumerator(standing), Enumerator(standing))
In [5]: c.state == c2.state
Out[5]: True
In [6]: c.State.mooing
Out[6]: Enumerator(mooing)
In [7]: c.State['mooing']
Out[7]: Enumerator(mooing)
In [8]: c.state = Cow.State.dead
In [9]: c.state == c2.state
Out[9]: False
In [10]: c.state == Cow.State.dead
Out[10]: True
In [11]: c.state == 'dead'
Out[11]: True
In [12]: c.state == Cow.State['dead']
Out[11]: True
使用下面的方法。
TYPE = {'EAN13': u'EAN-13',
'CODE39': u'Code 39',
'CODE128': u'Code 128',
'i25': u'Interleaved 2 of 5',}
>>> TYPE.items()
[('EAN13', u'EAN-13'), ('i25', u'Interleaved 2 of 5'), ('CODE39', u'Code 39'), ('CODE128', u'Code 128')]
>>> TYPE.keys()
['EAN13', 'i25', 'CODE39', 'CODE128']
>>> TYPE.values()
[u'EAN-13', u'Interleaved 2 of 5', u'Code 39', u'Code 128']
我用它来选择Django模型,它看起来非常python化。它不是一个真正的Enum,但它完成了这项工作。