我主要是c#开发人员,但我目前正在用Python开发一个项目。

我如何在Python中表示等价的Enum ?


当前回答

在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 Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

这比使用整数更有漏洞,因为你不必担心确保整数是唯一的(例如,如果你说Dog = 1和Cat = 1,你就完蛋了)。

它比使用字符串更防bug,因为你不必担心拼写错误(例如。 x == "猫"无声失败,但x ==动物。Catt是一个运行时异常)。


附录: 你甚至可以通过让Dog和Cat继承一个具有正确元类的符号类来增强这个解决方案:

class SymbolClass(type):
    def __repr__(self): return self.__qualname__
    def __str__(self): return self.__name__

class Symbol(metaclass=SymbolClass): pass


class Animal:
    class Dog(Symbol): pass
    class Cat(Symbol): pass

然后,如果你使用这些值来索引一个字典,请求它的表示将使它们看起来很漂亮:

>>> mydict = {Animal.Dog: 'Wan Wan', Animal.Cat: 'Nyaa'}
>>> mydict
{Animal.Dog: 'Wan Wan', Animal.Cat: 'Nyaa'}
def M_add_class_attribs(attribs):
    def foo(name, bases, dict_):
        for v, k in attribs:
            dict_[k] = v
        return type(name, bases, dict_)
    return foo

def enum(*names):
    class Foo(object):
        __metaclass__ = M_add_class_attribs(enumerate(names))
        def __setattr__(self, name, value):  # this makes it read-only
            raise NotImplementedError
    return Foo()

像这样使用它:

Animal = enum('DOG', 'CAT')
Animal.DOG # returns 0
Animal.CAT # returns 1
Animal.DOG = 2 # raises NotImplementedError

如果你只想要唯一的符号,不关心值,替换这行:

__metaclass__ = M_add_class_attribs(enumerate(names))

用这个:

__metaclass__ = M_add_class_attribs((object(), name) for name in names)

这是我见过的最好的一个:“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)

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']

我喜欢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

所有类变量都定义为元组,就像构造函数一样。到目前为止,还不能使用命名参数。