我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
我主要是c#开发人员,但我目前正在用Python开发一个项目。
我如何在Python中表示等价的Enum ?
当前回答
我用什么:
class Enum(object):
def __init__(self, names, separator=None):
self.names = names.split(separator)
for value, name in enumerate(self.names):
setattr(self, name.upper(), value)
def tuples(self):
return tuple(enumerate(self.names))
使用方法:
>>> state = Enum('draft published retracted')
>>> state.DRAFT
0
>>> state.RETRACTED
2
>>> state.FOO
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Enum' object has no attribute 'FOO'
>>> state.tuples()
((0, 'draft'), (1, 'published'), (2, 'retracted'))
这就给出了整数常数,比如状态。PUBLISHED和在Django模型中用作选项的二元组。
其他回答
在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
有关更多信息,请参阅提案。官方文件可能很快就会发布。
我喜欢Java枚举,这就是我在Python中的做法:
def enum(clsdef):
class Enum(object):
__slots__=tuple([var for var in clsdef.__dict__ if isinstance((getattr(clsdef, var)), tuple) and not var.startswith('__')])
def __new__(cls, *args, **kwargs):
if not '_the_instance' in cls.__dict__:
cls._the_instance = object.__new__(cls, *args, **kwargs)
return cls._the_instance
def __init__(self):
clsdef.values=lambda cls, e=Enum: e.values()
clsdef.valueOf=lambda cls, n, e=self: e.valueOf(n)
for ordinal, key in enumerate(self.__class__.__slots__):
args=getattr(clsdef, key)
instance=clsdef(*args)
instance._name=key
instance._ordinal=ordinal
setattr(self, key, instance)
@classmethod
def values(cls):
if not hasattr(cls, '_values'):
cls._values=[getattr(cls, name) for name in cls.__slots__]
return cls._values
def valueOf(self, name):
return getattr(self, name)
def __repr__(self):
return ''.join(['<class Enum (', clsdef.__name__, ') at ', str(hex(id(self))), '>'])
return Enum()
示例使用:
i=2
@enum
class Test(object):
A=("a",1)
B=("b",)
C=("c",2)
D=tuple()
E=("e",3)
while True:
try:
F, G, H, I, J, K, L, M, N, O=[tuple() for _ in range(i)]
break;
except ValueError:
i+=1
def __init__(self, name="default", aparam=0):
self.name=name
self.avalue=aparam
所有类变量都定义为元组,就像构造函数一样。到目前为止,还不能使用命名参数。
下面是亚历克·托马斯解决方案的一个变种:
def enum(*args, **kwargs):
return type('Enum', (), dict((y, x) for x, y in enumerate(args), **kwargs))
x = enum('POOH', 'TIGGER', 'EEYORE', 'ROO', 'PIGLET', 'RABBIT', 'OWL')
assert x.POOH == 0
assert x.TIGGER == 1
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)
在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