我主要是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',
))
其他回答
我喜欢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
所有类变量都定义为元组,就像构造函数一样。到目前为止,还不能使用命名参数。
Enum类可以是一行程序。
class Enum(tuple): __getattr__ = tuple.index
如何使用它(正向和反向查找、键、值、项等)
>>> State = Enum(['Unclaimed', 'Claimed'])
>>> State.Claimed
1
>>> State[1]
'Claimed'
>>> State
('Unclaimed', 'Claimed')
>>> range(len(State))
[0, 1]
>>> [(k, State[k]) for k in range(len(State))]
[(0, 'Unclaimed'), (1, 'Claimed')]
>>> [(k, getattr(State, k)) for k in State]
[('Unclaimed', 0), ('Claimed', 1)]
我需要在pyparsing中使用一些符号常量来表示二进制运算符的左右结合性。我像这样使用类常量:
# an internal class, not intended to be seen by client code
class _Constants(object):
pass
# an enumeration of constants for operator associativity
opAssoc = _Constants()
opAssoc.LEFT = object()
opAssoc.RIGHT = object()
现在当客户端代码想要使用这些常量时,他们可以使用以下方法导入整个枚举:
import opAssoc from pyparsing
枚举是唯一的,它们可以用'is'而不是'=='来测试,它们不会在我的代码中占用很大的空间,而且它们很容易导入到客户端代码中。它们不支持任何花哨的str()行为,但到目前为止,这属于YAGNI类别。
对于旧的Python 2.x
def enum(*sequential, **named):
enums = dict(zip(sequential, [object() for _ in range(len(sequential))]), **named)
return type('Enum', (), enums)
如果你命名它,是你的问题,但如果不创建对象而不是值允许你这样做:
>>> DOG = enum('BARK', 'WALK', 'SIT')
>>> CAT = enum('MEOW', 'WALK', 'SIT')
>>> DOG.WALK == CAT.WALK
False
当使用这里的其他实现时(在我的例子中使用命名实例时),必须确保永远不要尝试比较来自不同枚举的对象。这里有一个可能的陷阱:
>>> DOG = enum('BARK'=1, 'WALK'=2, 'SIT'=3)
>>> CAT = enum('WALK'=1, 'SIT'=2)
>>> pet1_state = DOG.BARK
>>> pet2_state = CAT.WALK
>>> pet1_state == pet2_state
True
呵!
有趣的是,前几天我正好需要这个,但我找不到一个值得使用的实现……所以我自己写了:
import functools
class EnumValue(object):
def __init__(self,name,value,type):
self.__value=value
self.__name=name
self.Type=type
def __str__(self):
return self.__name
def __repr__(self):#2.6 only... so change to what ever you need...
return '{cls}({0!r},{1!r},{2})'.format(self.__name,self.__value,self.Type.__name__,cls=type(self).__name__)
def __hash__(self):
return hash(self.__value)
def __nonzero__(self):
return bool(self.__value)
def __cmp__(self,other):
if isinstance(other,EnumValue):
return cmp(self.__value,other.__value)
else:
return cmp(self.__value,other)#hopefully their the same type... but who cares?
def __or__(self,other):
if other is None:
return self
elif type(self) is not type(other):
raise TypeError()
return EnumValue('{0.Name} | {1.Name}'.format(self,other),self.Value|other.Value,self.Type)
def __and__(self,other):
if other is None:
return self
elif type(self) is not type(other):
raise TypeError()
return EnumValue('{0.Name} & {1.Name}'.format(self,other),self.Value&other.Value,self.Type)
def __contains__(self,other):
if self.Value==other.Value:
return True
return bool(self&other)
def __invert__(self):
enumerables=self.Type.__enumerables__
return functools.reduce(EnumValue.__or__,(enum for enum in enumerables.itervalues() if enum not in self))
@property
def Name(self):
return self.__name
@property
def Value(self):
return self.__value
class EnumMeta(type):
@staticmethod
def __addToReverseLookup(rev,value,newKeys,nextIter,force=True):
if value in rev:
forced,items=rev.get(value,(force,()) )
if forced and force: #value was forced, so just append
rev[value]=(True,items+newKeys)
elif not forced:#move it to a new spot
next=nextIter.next()
EnumMeta.__addToReverseLookup(rev,next,items,nextIter,False)
rev[value]=(force,newKeys)
else: #not forcing this value
next = nextIter.next()
EnumMeta.__addToReverseLookup(rev,next,newKeys,nextIter,False)
rev[value]=(force,newKeys)
else:#set it and forget it
rev[value]=(force,newKeys)
return value
def __init__(cls,name,bases,atts):
classVars=vars(cls)
enums = classVars.get('__enumerables__',None)
nextIter = getattr(cls,'__nextitr__',itertools.count)()
reverseLookup={}
values={}
if enums is not None:
#build reverse lookup
for item in enums:
if isinstance(item,(tuple,list)):
items=list(item)
value=items.pop()
EnumMeta.__addToReverseLookup(reverseLookup,value,tuple(map(str,items)),nextIter)
else:
value=nextIter.next()
value=EnumMeta.__addToReverseLookup(reverseLookup,value,(str(item),),nextIter,False)#add it to the reverse lookup, but don't force it to that value
#build values and clean up reverse lookup
for value,fkeys in reverseLookup.iteritems():
f,keys=fkeys
for key in keys:
enum=EnumValue(key,value,cls)
setattr(cls,key,enum)
values[key]=enum
reverseLookup[value]=tuple(val for val in values.itervalues() if val.Value == value)
setattr(cls,'__reverseLookup__',reverseLookup)
setattr(cls,'__enumerables__',values)
setattr(cls,'_Max',max([key for key in reverseLookup] or [0]))
return super(EnumMeta,cls).__init__(name,bases,atts)
def __iter__(cls):
for enum in cls.__enumerables__.itervalues():
yield enum
def GetEnumByName(cls,name):
return cls.__enumerables__.get(name,None)
def GetEnumByValue(cls,value):
return cls.__reverseLookup__.get(value,(None,))[0]
class Enum(object):
__metaclass__=EnumMeta
__enumerables__=None
class FlagEnum(Enum):
@staticmethod
def __nextitr__():
yield 0
for val in itertools.count():
yield 2**val
def enum(name,*args):
return EnumMeta(name,(Enum,),dict(__enumerables__=args))
接受或离开它,它做了我需要它做的:)
像这样使用它:
class Air(FlagEnum):
__enumerables__=('None','Oxygen','Nitrogen','Hydrogen')
class Mammals(Enum):
__enumerables__=('Bat','Whale',('Dog','Puppy',1),'Cat')
Bool = enum('Bool','Yes',('No',0))