如何在Python中表示”枚举”?

How can I represent an 'Enum' in Python?

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

如何在python中表示枚举的等价物?


枚举已添加到python 3.4中,如PEP435所述。在PYPI上,它也被反向移植到3.3、3.2、3.1、2.7、2.6、2.5和2.4。

要获得更高级的枚举技术,请尝试aenum库(2.7、3.3+,与enum34的作者相同。代码在py2和py3之间不完全兼容,例如,在python 2中需要__order__

  • 使用enum34,做$ pip install enum34
  • 使用aenum,做$ pip install aenum

安装enum(无编号)将安装完全不同且不兼容的版本。

1
2
3
4
5
6
7
from enum import Enum     # for enum34, or the stdlib version
# from aenum import Enum  # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')

Animal.ant  # returns <Animal.ant: 1>
Animal['ant']  # returns <Animal.ant: 1> (string lookup)
Animal.ant.name  # returns 'ant' (inverse lookup)

或同等:

1
2
3
4
5
class Animal(Enum):
    ant = 1
    bee = 2
    cat = 3
    dog = 4

在早期版本中,实现枚举的一种方法是:

1
2
def enum(**enums):
    return type('Enum', (), enums)

使用方法如下:

1
2
3
4
5
6
7
>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'

您还可以通过以下方式轻松支持自动枚举:

1
2
3
def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    return type('Enum', (), enums)

像这样使用:

1
2
3
4
5
>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1

可以通过以下方式添加将值转换回名称的支持:

1
2
3
4
5
def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    reverse = dict((value, key) for key, value in enums.iteritems())
    enums['reverse_mapping'] = reverse
    return type('Enum', (), enums)

这将覆盖具有该名称的任何内容,但对于在输出中呈现枚举很有用。如果反向映射不存在,它将抛出keyror。第一个例子:

1
2
>>> Numbers.reverse_mapping['three']
'THREE'

在PEP435之前,python没有一个等价物,但您可以实现自己的。

我自己,我喜欢保持简单(我在网上看到过一些非常复杂的例子),就像这样……

1
2
3
4
5
class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

在Python3.4(PEP435)中,可以将枚举设置为基类。这使您获得了一点额外的功能,如PEP中所述。例如,枚举成员不同于整数,它们由namevalue组成。

1
2
3
4
5
6
7
8
9
10
11
12
class Animal(Enum):
    DOG = 1
    CAT = 2

print(Animal.DOG)
# <Animal.DOG: 1>

print(Animal.DOG.value)
# 1

print(Animal.DOG.name)
#"DOG"

如果不想键入值,请使用以下快捷方式:

1
2
class Animal(Enum):
    DOG, CAT = range(2)

Enum实现可以转换为列表,并且是可重写的。其成员的顺序是声明顺序,与它们的值无关。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Animal(Enum):
    DOG = 1
    CAT = 2
    COW = 0

list(Animal)
# [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.COW: 0>]

[animal.value for animal in Animal]
# [1, 2, 0]

Animal.CAT in Animal
# True


以下是一个实现:

1
2
3
4
5
class Enum(set):
    def __getattr__(self, name):
        if name in self:
            return name
        raise AttributeError

其用法如下:

1
2
3
Animals = Enum(["DOG","CAT","HORSE"])

print(Animals.DOG)


如果您需要数值,下面是最快的方法:

1
dog, cat, rabbit = range(3)

在python 3.x中,您还可以在末尾添加一个带星号的占位符,它将吸收该范围的所有剩余值,以防您不介意浪费内存,并且无法计算:

1
dog, cat, rabbit, horse, *_ = range(100)


对你来说,最好的解决方案将取决于你从你的假enum中需要什么。

简单枚举:

如果您只需要enum作为识别不同项目的名称列表,Mark Harrison(以上)的解决方案非常好:

1
Pen, Pencil, Eraser = range(0, 3)

使用range还可以设置任何起始值:

1
Pen, Pencil, Eraser = range(9, 12)

除上述内容外,如果您还要求这些项属于某种类型的容器,则将它们嵌入类中:

1
2
class Stationery:
    Pen, Pencil, Eraser = range(0, 3)

要使用枚举项,现在需要使用容器名称和项名称:

1
stype = Stationery.Pen

复合枚举:

对于枚举的长列表或更复杂的枚举使用,这些解决方案将不足够。您可以通过will-ware查看在python食谱中发布的用于模拟python枚举的配方。这里有一个在线版本。

更多信息:

PEP354:python中的枚举有关于python中枚举的建议的有趣细节,以及为什么拒绝它。


JavaPrdJDK 5中使用的类型安全枚举模式具有优势数量。就像在亚历山德罗的回答中,你创造了一个类和类级别字段是枚举值;但是,枚举值是类的实例,而不是小整数。这有枚举值不会无意中比较相等的优点对于小整数,可以控制它们的打印方式,添加任意方法如果有用并使用IsInstance进行断言:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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的一个线程指出,在野外有几个枚举库,包括:

  • 氟利昂
  • 勒姆
  • …和想象中命名的枚举

枚举的类可以一一线。

1
class Enum(tuple): __getattr__ = tuple.index

如何使用它(前馈和反向查找,关键的项目,价值观,等。)

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> 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)]

所以,我同意。让我们不要在Python中强制类型安全,但我想保护自己不受愚蠢错误的影响。那我们怎么看这个?

1
2
3
4
5
6
class Animal(object):
    values = ['Horse','Dog','Cat']

    class __metaclass__(type):
        def __getattr__(self, name):
            return self.values.index(name)

它使我在定义枚举时避免值冲突。

1
2
>>> Animal.Cat
2

还有一个便利的优势:快速的反向查找:

1
2
def name_of(self, i):
    return self.values[i]


python没有与Enum相同的内置版本,其他的答案也有实现自己的想法(您可能对python食谱中的超顶级版本感兴趣)。

但是,在C中调用Enum的情况下,我通常只使用简单的字符串:因为对象/属性的实现方式,(C)python被优化为可以很快地使用短字符串,所以使用整数不会有任何性能优势。为了防止输入错误/无效值,您可以在选定的位置插入检查。

1
2
3
4
5
ANIMALS = ['cat', 'dog', 'python']

def take_for_a_walk(animal):
    assert animal in ANIMALS
    ...

(与使用类相比,一个缺点是您失去了自动完成的好处)


在2013年05月10日圭附和说,两个接受PEP 435为3.4《Python标准库。这意味这终于有Python的内置支持enumerations!

有一backport可用Python 3.1 3.2 3.3,2.6,2.7,2.5和2.4。它的在线enum34 pypi AA。

说明:

1
2
3
4
5
>>> from enum import Enum
>>> class Color(Enum):
...     red = 1
...     green = 2
...     blue = 3

表示:

1
2
3
4
>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>

迭代:

1
2
3
4
5
6
>>> for color in Color:
...   print(color)
...
Color.red
Color.green
Color.blue

programmatic访问:

1
2
3
4
>>> Color(1)
Color.red
>>> Color['blue']
Color.blue

更多信息,参考两个建议。官方文件,可能会很快。


我喜欢用python定义枚举,如下所示:

1
2
3
4
5
class Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

它比使用整数更具防虫性,因为您不必担心确保整数是唯一的(例如,如果您说dog=1和cat=1,您将被拧紧)。

它比使用字符串更能防止错误,因为您不必担心打字错误(例如x=="catt"无提示失败,但x==animal.catt是运行时异常)。


1
2
3
4
5
6
7
8
9
10
11
12
13
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()

这样使用:

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

如果只需要唯一的符号,而不关心值,请替换此行:

1
__metaclass__ = M_add_class_attribs(enumerate(names))

用这个:

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


六羟甲基三聚氰胺六甲醚。。。我想最接近枚举的东西应该是一个字典,定义如下:

1
2
3
4
5
months = {
    'January': 1,
    'February': 2,
    ...
}

1
2
3
4
5
months = dict(
    January=1,
    February=2,
    ...
)

然后,您可以对如下常量使用符号名称:

1
mymonth = months['January']

还有其他选项,如元组列表或元组列表,但字典是唯一为您提供访问价值。

编辑:我也喜欢亚历山德罗的回答!


另一个非常简单的枚举在python中的实现,使用namedtuple

1
2
3
4
5
6
from collections import namedtuple

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

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

或者,或者,

1
2
3
4
5
6
7
# 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())

与上面的方法类似,set子类允许:

1
2
3
'FOO' in MyEnum
other = MyEnum.FOO
assert other == MyEnum.FOO

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

1
MyEnum.FOO < MyEnum.BAR

如果使用填充序列号值的版本,则按预期操作。


在python 3.4中,将提供对枚举的官方支持。您可以在python 3.4文档页面上找到文档和示例。

Enumerations are created using the class syntax, which makes them easy
to read and write. An alternative creation method is described in
Functional API. To define an enumeration, subclass Enum as follows:

1
2
3
4
5
from enum import Enum
class Color(Enum):
     red = 1
     green = 2
     blue = 3


我用什么:

1
2
3
4
5
6
7
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))

如何使用:

1
2
3
4
5
6
7
8
9
10
11
>>> 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'))

所以这就给了你整数常量,比如state.published和两个tuple,在django模型中作为选择。


大卫格建议使用口述。我会更进一步,使用套装:

1
months = set('January', 'February', ..., 'December')

现在,您可以这样测试一个值是否与集合中的某个值匹配:

1
if m in months:

不过,和df一样,我通常只使用字符串常量代替枚举。


这是我见过的最好的一个:"Python中的第一类枚举"

http://code.activestate.com/recipes/413486/

它为您提供一个类,并且该类包含所有枚举。枚举可以相互比较,但没有任何特定的值;不能将它们用作整数值。(一开始我抵制这个,因为我习惯于C枚举,这是整数值。但是如果你不能把它作为一个整数来使用,你就不能错误地把它作为一个整数来使用,所以总的来说,我认为它是一个胜利。)每个枚举都是一个唯一的值。可以打印枚举,可以对其进行迭代,可以测试枚举值是否在枚举中。它很完整,很光滑。

编辑(CFI):上面的链接与python 3不兼容。这是我的enum.py到python 3的端口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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( '
*** 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)

保持简单:

1
2
3
4
5
6
class Enum(object):
    def __init__(self, tupleList):
            self.tupleList = tupleList

    def __getattr__(self, name):
            return self.tupleList.index(name)

然后:

1
2
3
DIRECTION = Enum(('UP', 'DOWN', 'LEFT', 'RIGHT'))
DIRECTION.DOWN
1


为了解码二进制文件格式,我曾经需要一个枚举类。我碰巧想要的功能是简洁的枚举定义、通过整数值或字符串自由创建枚举实例的能力,以及一个有用的repr表示。我的结论是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
>>> class Enum(int):
...     def __new__(cls, value):
...         if isinstance(value, str):
...             return getattr(cls, value)
...         elif isinstance(value, int):
...             return cls.__index[value]
...     def __str__(self): return self.__name
...     def __repr__(self): return"%s.%s" % (type(self).__name__, self.__name)
...     class __metaclass__(type):
...         def __new__(mcls, name, bases, attrs):
...             attrs['__slots__'] = ['_Enum__name']
...             cls = type.__new__(mcls, name, bases, attrs)
...             cls._Enum__index = _index = {}
...             for base in reversed(bases):
...                 if hasattr(base, '_Enum__index'):
...                     _index.update(base._Enum__index)
...             # create all of the instances of the new class
...             for attr in attrs.keys():
...                 value = attrs[attr]
...                 if isinstance(value, int):
...                     evalue = int.__new__(cls, value)
...                     evalue._Enum__name = attr
...                     _index[value] = evalue
...                     setattr(cls, attr, evalue)
...             return cls
...

使用它的异想天开的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
>>> class Citrus(Enum):
...     Lemon = 1
...     Lime = 2
...
>>> Citrus.Lemon
Citrus.Lemon
>>>
>>> Citrus(1)
Citrus.Lemon
>>> Citrus(5)
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
  File"<stdin>", line 6, in __new__
KeyError: 5
>>> class Fruit(Citrus):
...     Apple = 3
...     Banana = 4
...
>>> Fruit.Apple
Fruit.Apple
>>> Fruit.Lemon
Citrus.Lemon
>>> Fruit(1)
Citrus.Lemon
>>> Fruit(3)
Fruit.Apple
>>>"%d %s %r" % ((Fruit.Apple,)*3)
'3 Apple Fruit.Apple'
>>> Fruit(1) is Citrus.Lemon
True

主要特点:

  • str()int()repr()都可以生成最有用的输出,分别是枚举的名称、它的整数值和计算返回枚举的python表达式。
  • 构造函数返回的枚举值严格限制为预定义的值,没有意外的枚举值。
  • 枚举值为单件,可与is严格比较。

纽约标准Python的冰在PEP 435个,所以可枚举类将在未来版本的Python。

1
>>> from enum import Enum

然而,两个开始使用它,你可以安装在原有的图书馆,激励的PEP:

1
$ pip install flufl.enum

然后你可以使用它,根据它的在线指南:

1
2
3
4
5
6
7
8
9
>>> from flufl.enum import Enum
>>> class Colors(Enum):
...     red = 1
...     green = 2
...     blue = 3
>>> for color in Colors: print color
Colors.red
Colors.green
Colors.blue

我真的很喜欢-托马斯的溶液(http:/ / / / stackoverflow.com 1695250):

1
2
3
def enum(**enums):
    '''simple constant"enums"'''
    return type('Enum', (object,), enums)

它的优雅,干净的很,但这只是一个功能,创建一个类的属性与specified。

有一个小的修改的功能,我们可以得到它的两个法案的enumy更多一点的:

NOTE: I created the following examples by trying to reproduce the
behavior of pygtk's new style 'enums' (like Gtk.MessageType.WARNING)

1
2
3
4
5
6
7
def enum_base(t, **enums):
    '''enums with a base class'''
    T = type('Enum', (t,), {})
    for key,val in enums.items():
        setattr(T, key, T(val))

    return T

这是创建一个基于断specified枚举类型。在添加属性存取给像我以前behaves AS网络功能,你会期望两个枚举登两大类。它也inherits的基础类。

例如,整数枚举。

1
2
3
4
5
6
7
8
9
10
11
12
>>> Numbers = enum_base(int, ONE=1, TWO=2, THREE=3)
>>> Numbers.ONE
1
>>> x = Numbers.TWO
>>> 10 + x
12
>>> type(Numbers)
<type 'type'>
>>> type(Numbers.ONE)
<class 'Enum'>
>>> isinstance(x, Numbers)
True

另一个有趣的事情,可以用这个方法做冰customize特异性行为的城市overriding内置的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def enum_repr(t, **enums):
    '''enums with a base class and repr() output'''
    class Enum(t):
        def __repr__(self):
            return '<enum {0} of type Enum({1})>'.format(self._name, t.__name__)

    for key,val in enums.items():
        i = Enum(val)
        i._name = key
        setattr(Enum, key, i)

    return Enum



>>> Numbers = enum_repr(int, ONE=1, TWO=2, THREE=3)
>>> repr(Numbers.ONE)
'<enum ONE of type Enum(int)>'
>>> str(Numbers.ONE)
'1'

1
2
3
def enum(*sequential, **named):
    enums = dict(zip(sequential, [object() for _ in range(len(sequential))]), **named)
    return type('Enum', (), enums)

如果命名它,是您的问题,但如果不创建对象而不是值,则允许您这样做:

1
2
3
4
>>> DOG = enum('BARK', 'WALK', 'SIT')
>>> CAT = enum('MEOW', 'WALK', 'SIT')
>>> DOG.WALK == CAT.WALK
False

当使用位于此处的其他实现时(在我的示例中使用命名实例时),必须确保从不尝试比较来自不同枚举的对象。因为这里有一个可能的陷阱:

1
2
3
4
5
6
>>> 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

伊克斯!


pypi中的枚举包提供了一个健壮的枚举实现。先前的回答提到了PEP 354;这被拒绝,但提案得到了实施。http://pypi.python.org/pypi/enum.

使用简单优雅:

1
2
3
4
5
6
7
8
9
10
>>> from enum import Enum
>>> Colors = Enum('red', 'blue', 'green')
>>> shirt_color = Colors.green
>>> shirt_color = Colors[2]
>>> shirt_color > Colors.red
True
>>> shirt_color.index
2
>>> str(shirt_color)
'green'


Alexandru建议对枚举使用类常量,效果相当好。

我还喜欢为每一组常量添加一个字典,以查找人类可读的字符串表示形式。

这有两个用途:a)它提供了一种简单的方法来漂亮地打印枚举;b)字典逻辑地对常量进行分组,以便测试成员身份。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Animal:    
  TYPE_DOG = 1
  TYPE_CAT = 2

  type2str = {
    TYPE_DOG:"dog",
    TYPE_CAT:"cat"
  }

  def __init__(self, type_):
    assert type_ in self.type2str.keys()
    self._type = type_

  def __repr__(self):
    return"<%s type=%s>" % (
        self.__class__.__name__, self.type2str[self._type].upper())

这里的方法是由一些不同的特点:找到有价值

  • 允许>和<比较基于阶的枚举,不lexical阶
  • 我市地址item name或性能指标:X.A x [ A ]或[ ] X 0
  • 支状切片操作:[ ]或[ 1 ]

和大多数的importantly防止比较之间的不同类型的枚举。

基于在线closely http:/ / / / code.activestate.com recipes 413486第一级,在Python的枚举。

这里包括两个多doctests illustrate什么的,这是不同的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
def enum(*names):
   """
SYNOPSIS
    Well-behaved enumerated type, easier than creating custom classes

DESCRIPTION
    Create a custom type that implements an enumeration.  Similar in concept
    to a C enum but with some additional capabilities and protections.  See
    http://code.activestate.com/recipes/413486-first-class-enums-in-python/.

PARAMETERS
    names       Ordered list of names.  The order in which names are given
                will be the sort order in the enum type.  Duplicate names
                are not allowed.  Unicode names are mapped to ASCII.

RETURNS
    Object of type enum, with the input names and the enumerated values.

EXAMPLES
    >>> letters = enum('a','e','i','o','u','b','c','y','z')
    >>> letters.a < letters.e
    True

    ## index by property
    >>> letters.a
    a

    ## index by position
    >>> letters[0]
    a

    ## index by name, helpful for bridging string inputs to enum
    >>> letters['a']
    a

    ## sorting by order in the enum() create, not character value
    >>> letters.u < letters.b
    True

    ## normal slicing operations available
    >>> letters[-1]
    z

    ## error since there are not 100 items in enum
    >>> letters[99]
    Traceback (most recent call last):
        ...
    IndexError: tuple index out of range

    ## error since name does not exist in enum
    >>> letters['ggg']
    Traceback (most recent call last):
        ...
    ValueError: tuple.index(x): x not in tuple

    ## enums must be named using valid Python identifiers
    >>> numbers = enum(1,2,3,4)
    Traceback (most recent call last):
        ...
    AssertionError: Enum values must be string or unicode

    >>> a = enum('-a','-b')
    Traceback (most recent call last):
        ...
    TypeError: Error when calling the metaclass bases
        __slots__ must be identifiers

    ## create another enum
    >>> tags = enum('a','b','c')
    >>> tags.a
    a
    >>> letters.a
    a

    ## can't compare values from different enums
    >>> letters.a == tags.a
    Traceback (most recent call last):
        ...
    AssertionError: Only values from the same enum are comparable

    >>> letters.a < tags.a
    Traceback (most recent call last):
        ...
    AssertionError: Only values from the same enum are comparable

    ## can't update enum after create
    >>> letters.a = 'x'
    Traceback (most recent call last):
        ...
    AttributeError: 'EnumClass' object attribute 'a' is read-only

    ## can't update enum after create
    >>> del letters.u
    Traceback (most recent call last):
        ...
    AttributeError: 'EnumClass' object attribute 'u' is read-only

    ## can't have non-unique enum values
    >>> x = enum('a','b','c','a')
    Traceback (most recent call last):
        ...
    AssertionError: Enums must not repeat values

    ## can't have zero enum values
    >>> x = enum()
    Traceback (most recent call last):
        ...
    AssertionError: Empty enums are not supported

    ## can't have enum values that look like special function names
    ## since these could collide and lead to non-obvious errors
    >>> x = enum('a','b','c','__cmp__')
    Traceback (most recent call last):
        ...
    AssertionError: Enum values beginning with __ are not supported

LIMITATIONS
    Enum values of unicode type are not preserved, mapped to ASCII instead.

   """

    ## must have at least one enum value
    assert names, 'Empty enums are not supported'
    ## enum values must be strings
    assert len([i for i in names if not isinstance(i, types.StringTypes) and not \
        isinstance(i, unicode)]) == 0, 'Enum values must be string or unicode'
    ## enum values must not collide with special function names
    assert len([i for i in names if i.startswith("__")]) == 0,\
        'Enum values beginning with __ are not supported'
    ## each enum value must be unique from all others
    assert names == uniquify(names), 'Enums must not repeat values'

    class EnumClass(object):
       """ See parent function for explanation"""

        __slots__ = names

        def __iter__(self):
            return iter(constants)

        def __len__(self):
            return len(constants)

        def __getitem__(self, i):
            ## this makes xx['name'] possible
            if isinstance(i, types.StringTypes):
                i = names.index(i)
            ## handles the more normal xx[0]
            return constants[i]

        def __repr__(self):
            return 'enum' + str(names)

        def __str__(self):
            return 'enum ' + str(constants)

        def index(self, i):
            return names.index(i)

    class EnumValue(object):
       """ See parent function for explanation"""

        __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):
            assert self.enumtype is other.enumtype, 'Only values from the same enum are comparable'
            return cmp(self.value, other.value)

        def __invert__(self):
            return constants[maximum - self.value]

        def __nonzero__(self):
            ## return bool(self.value)
            ## Original code led to bool(x[0])==False, not correct
            return True

        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

以下是亚历克·托马斯解决方案的变体:

1
2
3
4
5
6
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


当这原始的枚举的建议是,PEP 354年前了,让它来备份。这是一种枚举的意图被添加到3.2,但它有两个3.3例如后才被忘却。和现在有一用于在PEP 435在Python 3.4。《参考执行flufl.enumPEP 435冰。

在2013年4月,似乎有一个共识,一般的东西应该是加了两个标准的图书馆在3.4-as长可以为人民agree -什么是"应该是什么"。这是硬的一方。看到这里和这里启动线程和其他线程的打一个月的早期大学2013年。

同时,每一个小时,这是上一摆,新的设计和实现等appear在线pypi,activestate等,所以如果你不喜欢这个flufl尝试设计一pypi搜索。


此解决方案是获取定义为列表的枚举类的简单方法(不再有烦人的整数赋值):

枚举

1
2
3
4
5
6
import new

def create(class_name, names):
    return new.classobj(
        class_name, (object,), dict((y, x) for x, y in enumerate(names))
    )

PYP:

1
2
3
4
5
6
7
8
9
10
import enumeration

Colors = enumeration.create('Colors', (
    'red',
    'orange',
    'yellow',
    'green',
    'blue',
    'violet',
))

A型(以支持两个值的枚举得到的名字)两个亚力克-托马斯的整洁的回答:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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']

我在这里找到了一个很好的python配方:http://code.activestate.com/recipes/577024-yet-another-enum-for-python/

1
2
3
4
5
6
7
def enum(typename, field_names):
   "Create a new enumeration type"

    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    d = dict((reversed(nv) for nv in enumerate(field_names)), __slots__ = ())
    return type(typename, (object,), d)()

示例用法:

1
STATE = enum('STATE', 'GET_QUIZ, GET_VERSE, TEACH')

更多详细信息可以在配方页面上找到。


在答案列表中没有看到这个,这是我抽出来的。它允许使用"in"关键字和len()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class EnumTypeError(TypeError):
    pass

class Enum(object):
   """
    Minics enum type from different languages
    Usage:
    Letters = Enum(list('abc'))
    a = Letters.a
    print(a in Letters) # True
    print(54 in Letters) # False
   """

    def __init__(self, enums):
        if isinstance(enums, dict):
            self.__dict__.update(enums)
        elif isinstance(enums, list) or isinstance(enums, tuple):
            self.__dict__.update(**dict((v,k) for k,v in enumerate(enums)))
        else:
            raise EnumTypeError

    def __contains__(self, key):
        return key in self.__dict__.values()

    def __len__(self):
        return len(self.__dict__.values())


if __name__ == '__main__':
    print('Using a dictionary to create Enum:')
    Letters = Enum(dict((v,k) for k,v in enumerate(list('abcde'))))
    a = Letters.a
    print('\tIs a in e?', a in Letters)
    print('\tIs 54 in e?', 54 in Letters)
    print('\tLength of Letters enum:', len(Letters))

    print('
Using a list to create Enum:'
)
    Letters = Enum(list('abcde'))
    a = Letters.a
    print('\tIs a in e?', a in Letters)
    print('\tIs 54 in e?', 54 in Letters)
    print('\tLength of Letters enum:', len(Letters))

    try:
        # make sure we raise an exception if we pass an invalid arg
        Failure = Enum('This is a Failure')
        print('Failure')
    except EnumTypeError:
        print('Success!')

输出:

1
2
3
4
5
6
7
8
9
10
Using a dictionary to create Enum:
        Is a in e? True
        Is 54 in e? False
        Length of Letters enum: 5

Using a list to create Enum:
        Is a in e? True
        Is 54 in e? False
        Length of Letters enum: 5
Success!


有趣的是,前几天我就需要这样做,我找不到一个值得使用的实现…所以我写了自己的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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))

要么接受要么放弃,它做了我需要它做的事情:)

像这样使用它:

1
2
3
4
5
6
class Air(FlagEnum):
    __enumerables__=('None','Oxygen','Nitrogen','Hydrogen')

class Mammals(Enum):
    __enumerables__=('Bat','Whale',('Dog','Puppy',1),'Cat')
Bool = enum('Bool','Yes',('No',0))

在Pyparsing中,我需要一些符号常量来表示二进制运算符的左右结合性。我使用了这样的类常量:

1
2
3
4
5
6
7
8
9
# 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()

现在,当客户端代码想要使用这些常量时,它们可以使用以下方法导入整个枚举:

1
import opAssoc from pyparsing

枚举是唯一的,它们可以用"is"而不是"=="进行测试,它们不会占用我的代码中的一个小概念,而且它们很容易导入到客户机代码中。它们不支持任何花哨的str()行为,但到目前为止,这属于yagni类别。


"这是我经常使用的解决方案,这是一个很简单的功能,一个动力创造了审级。

1
2
3
4
def enum(names):
   "Create a simple enumeration having similarities to C."
    return type('enum', (), dict(map(reversed, enumerate(
        names.replace(',', ' ').split())), __slots__=()))()

它是用简单的AA AA呼叫的功能与一个字符串具有的名字,你所有的参考。

1
2
grade = enum('A B C D F')
state = enum('awake, sleeping, dead')

《integers值是真的,所以你可以把大学的优势,如果desired(就像在C语言)。

1
2
3
4
5
6
7
8
>>> grade.A
0
>>> grade.B
1
>>> grade.F == 4
True
>>> state.dead == 2
True

为什么枚举必须是整数?不幸的是,在不更改Python语言的情况下,我想不出任何好看的构造来生成它,因此我将使用字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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)

然后,为了配置文件或其他远程输入,我们可以自然地对字符串进行测试,也许现在更好了。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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

在使用一个元类的两个实施enumeration(在我的思想,它是一个教育)。这里是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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()

Python 2.7和找到_ name()

这是一个简单的读两行的选择理念与一些辅助方法,这也许是更多的语言和使用清洁的两个比"逆向_映射"。requires Python > = 2.7。

两个地址下面的一些评论,枚举类型是有用的预防意识的拼写错误代码,例如国家机器,classifiers误差等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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)

在Aaron Maenpaa提出的Java-EnUM实现之后,我提出了以下几点。其想法是使其成为通用的和可解析的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class Enum:
    #'''
    #Java like implementation for enums.
    #
    #Usage:
    #class Tool(Enum): name = 'Tool'
    #Tool.DRILL = Tool.register('drill')
    #Tool.HAMMER = Tool.register('hammer')
    #Tool.WRENCH = Tool.register('wrench')
    #'''

    name = 'Enum'    # Enum name
    _reg = dict([])   # Enum registered values

    @classmethod
    def register(cls, value):
        #'''
        #Registers a new value in this enum.
        #
        #@param value: New enum value.
        #
        #@return: New value wrapper instance.
        #'''
        inst = cls(value)
        cls._reg[value] = inst
        return inst

    @classmethod
    def parse(cls, value):
        #'''
        #Parses a value, returning the enum instance.
        #
        #@param value: Enum value.
        #
        #@return: Value corresp instance.        
        #'''
        return cls._reg.get(value)    

    def __init__(self, value):
        #'''
        #Constructor (only for internal use).
        #'''
        self.value = value

    def __str__(self):
        #'''
        #str() overload.
        #'''
        return self.value

    def __repr__(self):
        #'''
        #repr() overload.
        #'''
        return"<" + self.name +":" + self.value +">"


我喜欢JavaEnUM,这就是我在Python中所做的事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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()

样品使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

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


我喜欢使用AA enumerations列表或集合。例如:

1
2
3
4
5
6
>>> packet_types = ['INIT', 'FINI', 'RECV', 'SEND']
>>> packet_types.index('INIT')
0
>>> packet_types.index('FINI')
1
>>>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def enum( *names ):

    '''
    Makes enum.
    Usage:
        E = enum( 'YOUR', 'KEYS', 'HERE' )
        print( E.HERE )
    '''


    class Enum():
        pass
    for index, name in enumerate( names ):
        setattr( Enum, name, index )
    return Enum

使用以下内容。

1
2
3
4
5
6
7
8
9
10
11
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']

我用它来选择姜戈模型,它看起来很像Python。它实际上不是一个枚举,但它完成了工作。