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

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


当前回答

使用下面的方法。

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,但它完成了这项工作。

其他回答

我喜欢在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'}

这个解决方案是获取定义为列表的枚举类的简单方法(没有更多烦人的整数赋值):

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',
))

另一个非常简单的Python枚举实现,使用namedtuple:

from collections import namedtuple

def enum(*keys):
    return namedtuple('Enum', keys)(*keys)

MyEnum = enum('FOO', 'BAR', 'BAZ')

,或者

# With sequential number values
def enum(*keys):
    return namedtuple('Enum', keys)(*range(len(keys)))

# From a dict / keyword args
def enum(**kwargs):
    return namedtuple('Enum', kwargs.keys())(*kwargs.values())




# Example for dictionary param:
values = {"Salad": 20, "Carrot": 99, "Tomato": "No i'm not"} 
Vegetables= enum(**values)

# >>> print(Vegetables.Tomato)        'No i'm not'


# Example for keyworded params: 
Fruits = enum(Apple="Steve Jobs", Peach=1, Banana=2)

# >>> print(Fruits.Apple)             'Steve Jobs'

就像上面子类设置的方法一样,这允许:

'FOO' in MyEnum
other = MyEnum.FOO
assert other == MyEnum.FOO

但是具有更大的灵活性,因为它可以有不同的键和值。这允许

MyEnum.FOO < MyEnum.BAR

如果使用填充连续数字值的版本,则按预期操作。

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 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)