# python-3.x intenum用法 - 我如何在Python中表示'Enum'？

2.7 python2 (25)

``````class Animal:
class Dog: pass
class Cat: pass

x = Animal.Dog
``````

``````class Animal:
DOG = 1
CAT = 2

x = Animal.DOG
``````

``````class Animal(Enum):
DOG = 1
CAT = 2

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

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

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

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

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

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

PEP 435中所述，Enum已經被添加到Python 3.4中。 它在pypi上也回到3.3,3.2,3.1,2.7,2.6,2.5 和2.4

• 要使用`enum34` ，請執行`\$ pip install enum34`
• 要使用`aenum` ，請執行`\$ pip install aenum`

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

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

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

``````>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'
``````

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

``````>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1
``````

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

``````>>> Numbers.reverse_mapping['three']
'THREE'
``````

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

``````dog, cat, rabbit = range(3)
``````

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

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

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

``````class Animal(object):
values = ['Horse','Dog','Cat']

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

``````>>> Animal.Cat
2
``````

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

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

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

I had need of some symbolic constants in pyparsing to represent left and right associativity of binary operators. I used class constants like this:

``````# 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()
``````

Now when client code wants to use these constants, they can import the entire enum using:

``````import opAssoc from pyparsing
``````

JDK 5以前版本中使用的類型安全枚舉模式具有許多優點。 就像亞歷山德魯的回答一樣，你創建一個類和類級別字段是枚舉值; 然而，枚舉值是類的實例，而不是小整數。 這樣做的好處是你的枚舉值不會無意中等於小整數，你可以控制它們的打印方式，如果有用的話添加任意方法並使用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最近的一篇文章指出，在野外有兩個枚舉庫，包括：

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

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

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

``````class Enum(set):
def __getattr__(self, name):
if name in self:
return name
raise AttributeError
``````

``````Animals = Enum(["DOG", "CAT", "HORSE"])

print(Animals.DOG)
``````

Python中的新標準是PEP 435 ，因此Enum類將在未來版本的Python中可用：

``````>>> from enum import Enum
``````

``````#sudo pip install flufl.enum   //or #sudo easy_install flufl.enum
``````

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

While the original enum proposal, PEP 354 , was rejected years ago, it keeps coming back up. Some kind of enum was intended to be added to 3.2, but it got pushed back to 3.3 and then forgotten. And now there's a PEP 435 intended for inclusion in Python 3.4. The reference implementation of PEP 435 is `flufl.enum` .

As of April 2013, there seems to be a general consensus that something should be added to the standard library in 3.4—as long as people can agree on what that "something" should be. That's the hard part. See the threads starting here and here , and a half dozen other threads in the early months of 2013.

Meanwhile, every time this comes up, a slew of new designs and implementations appear on PyPI, ActiveState, etc., so if you don't like the FLUFL design, try a PyPI search .

Here's an approach with some different characteristics I find valuable:

• allows > and < comparison based on order in enum, not lexical order
• can address item by name, property or index: xa, x['a'] or x[0]
• supports slicing operations like [:] or [-1]

and most importantly prevents comparisons between enums of different types !

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

``````class Enum(object):
def __init__(self, tupleList):
self.tupleList = tupleList

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

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

``````months = {
'January': 1,
'February': 2,
...
}
``````

``````months = dict(
January=1,
February=2,
...
)
``````

``````mymonth = months['January']
``````

PyPI的枚舉包提供了強大的枚舉實現。 較早的答案提到PEP 354; 這被拒絕了，但是提案被實施了http://pypi.python.org/pypi/enum

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

``````>>> 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
...
``````

``````>>> 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()`都會產生可能的最有用的輸出，分別是enumartion的名稱，整數值和返回枚舉的Python表達式。
• 由構造函數返回的枚舉值嚴格限制為預定義的值，而不是意外的枚舉值。
• 枚舉值是單身人士; 他們可以嚴格比較`is`

``````{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}
``````