from enum importEnum# for enum34, or the stdlib version# from aenum import Enum # for the aenum versionAnimal=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)
For more advanced Enum techniques try the aenum library (2.7, 3.3+, same author as enum34. Code is not perfectly compatible between py2 and py3, e.g. you’ll need __order__ in python 2).
To use enum34, do $ pip install enum34
To use aenum, do $ pip install aenum
Installing enum (no numbers) will install a completely different and incompatible version.
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)
or equivalently:
class Animal(Enum):
ant = 1
bee = 2
cat = 3
dog = 4
In earlier versions, one way of accomplishing enums is:
Support for converting the values back to names can be added this way:
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)
This overwrites anything with that name, but it is useful for rendering your enums in output. It will throw KeyError if the reverse mapping doesn’t exist. With the first example:
Before PEP 435, Python didn’t have an equivalent but you could implement your own.
Myself, I like keeping it simple (I’ve seen some horribly complex examples on the net), something like this …
class Animal:
DOG = 1
CAT = 2
x = Animal.DOG
In Python 3.4 (PEP 435), you can make Enum the base class. This gets you a little bit of extra functionality, described in the PEP. For example, enum members are distinct from integers, and they are composed of a name and a value.
class Animal(Enum):
DOG = 1
CAT = 2
print(Animal.DOG)
# <Animal.DOG: 1>
print(Animal.DOG.value)
# 1
print(Animal.DOG.name)
# "DOG"
If you don’t want to type the values, use the following shortcut:
class Animal(Enum):
DOG, CAT = range(2)
Enum implementations can be converted to lists and are iterable. The order of its members is the declaration order and has nothing to do with their values. For example:
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
回答 2
这是一个实现:
classEnum(set):def __getattr__(self, name):if name in self:return nameraiseAttributeError
If you need the numeric values, here’s the quickest way:
dog, cat, rabbit = range(3)
In Python 3.x you can also add a starred placeholder at the end, which will soak up all the remaining values of the range in case you don’t mind wasting memory and cannot count:
The best solution for you would depend on what you require from your fakeenum.
Simple enum:
If you need the enum as only a list of names identifying different items, the solution by Mark Harrison (above) is great:
Pen, Pencil, Eraser = range(0, 3)
Using a range also allows you to set any starting value:
Pen, Pencil, Eraser = range(9, 12)
In addition to the above, if you also require that the items belong to a container of some sort, then embed them in a class:
class Stationery:
Pen, Pencil, Eraser = range(0, 3)
To use the enum item, you would now need to use the container name and the item name:
stype = Stationery.Pen
Complex enum:
For long lists of enum or more complicated uses of enum, these solutions will not suffice. You could look to the recipe by Will Ware for Simulating Enumerations in Python published in the Python Cookbook. An online version of that is available here.
The typesafe enum pattern which was used in Java pre-JDK 5 has a
number of advantages. Much like in Alexandru’s answer, you create a
class and class level fields are the enum values; however, the enum
values are instances of the class rather than small integers. This has
the advantage that your enum values don’t inadvertently compare equal
to small integers, you can control how they’re printed, add arbitrary
methods if that’s useful and make assertions using 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
A recent thread on python-dev pointed out there are a couple of enum libraries in the wild, including:
>>>State=Enum(['Unclaimed','Claimed'])>>>State.Claimed1>>>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 inState][('Unclaimed',0),('Claimed',1)]
Python doesn’t have a built-in equivalent to enum, and other answers have ideas for implementing your own (you may also be interested in the over the top version in the Python cookbook).
However, in situations where an enum would be called for in C, I usually end up just using simple strings: because of the way objects/attributes are implemented, (C)Python is optimized to work very fast with short strings anyway, so there wouldn’t really be any performance benefit to using integers. To guard against typos / invalid values you can insert checks in selected places.
On 2013-05-10, Guido agreed to accept PEP 435 into the Python 3.4 standard library. This means that Python finally has builtin support for enumerations!
There is a backport available for Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4. It’s on Pypi as enum34.
Declaration:
>>> from enum import Enum
>>> class Color(Enum):
... red = 1
... green = 2
... blue = 3
class Animal:
class Dog: pass
class Cat: pass
x = Animal.Dog
It’s more bug-proof than using integers since you don’t have to worry about ensuring that the integers are unique (e.g. if you said Dog = 1 and Cat = 1 you’d be screwed).
It’s more bug-proof than using strings since you don’t have to worry about typos (e.g.
x == “catt” fails silently, but x == Animal.Catt is a runtime exception).
回答 11
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):classFoo(object):
__metaclass__ = M_add_class_attribs(enumerate(names))def __setattr__(self, name, value):# this makes it read-onlyraiseNotImplementedErrorreturnFoo()
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()
Hmmm… I suppose the closest thing to an enum would be a dictionary, defined either like this:
months = {
'January': 1,
'February': 2,
...
}
or
months = dict(
January=1,
February=2,
...
)
Then, you can use the symbolic name for the constants like this:
mymonth = months['January']
There are other options, like a list of tuples, or a tuple of tuples, but the dictionary is the only one that provides you with a “symbolic” (constant string) way to access the
value.
Edit: I like Alexandru’s answer too!
回答 13
另一个非常简单的Python枚举实现,使用namedtuple:
from collections import namedtuple
def enum(*keys):return namedtuple('Enum', keys)(*keys)MyEnum= enum('FOO','BAR','BAZ')
或者,
# With sequential number valuesdef enum(*keys):return namedtuple('Enum', keys)(*range(len(keys)))# From a dict / keyword argsdef enum(**kwargs):return namedtuple('Enum', kwargs.keys())(*kwargs.values())
就像上面子类的方法一样set,这允许:
'FOO'inMyEnum
other =MyEnum.FOO
assert other ==MyEnum.FOO
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:
from enum import Enum
class Color(Enum):
red = 1
green = 2
blue = 3
回答 15
我用什么:
classEnum(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'))
def cmp(a,b):if a < b:return-1if b < a:return1return0defEnum(*names):##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!classEnumClass(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)classEnumValue(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.EnumTypeis other.EnumType,"Only values from the same enum are comparable"return cmp(self.__value, other.__value)def __lt__(self, other):return self.__cmp__(other)<0def __eq__(self, other):return self.__cmp__(other)==0def __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()returnEnumTypeif __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 inDays:print('Day:', each)print('--- Yes/No ---')Confirmation=Enum('No','Yes')
answer =Confirmation.Noprint('Your answer is not',~answer)
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.
Edit (cfi): The above link is not Python 3 compatible. Here’s my port of enum.py to 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)
>>>classEnum(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
...
一个奇特的使用示例:
>>>classCitrus(Enum):...Lemon=1...Lime=2...>>>Citrus.LemonCitrus.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>>>classFruit(Citrus):...Apple=3...Banana=4...>>>Fruit.AppleFruit.Apple>>>Fruit.LemonCitrus.Lemon>>>Fruit(1)Citrus.Lemon>>>Fruit(3)Fruit.Apple>>>"%d %s %r"%((Fruit.Apple,)*3)'3 Apple Fruit.Apple'>>>Fruit(1)isCitrus.LemonTrue
I have had occasion to need of an Enum class, for the purpose of decoding a binary file format. The features I happened to want is concise enum definition, the ability to freely create instances of the enum by either integer value or string, and a useful representation. Here’s what I ended up with:
>>> 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
...
A whimsical example of using it:
>>> 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
Key features:
str(), int() and repr() all produce the most useful output possible, respectively the name of the enumartion, its integer value, and a Python expression that evaluates back to the enumeration.
Enumerated values returned by the constructor are limited strictly to the predefined values, no accidental enum values.
Enumerated values are singletons; they can be strictly compared with is
>>>from flufl.enum importEnum>>>classColors(Enum):... red =1... green =2... blue =3>>>for color inColors:print color
Colors.red
Colors.green
Colors.blue
>>> 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
回答 21
def enum(*sequential,**named):
enums = dict(zip(sequential,[object()for _ in range(len(sequential))]),**named)return type('Enum',(), enums)
When using other implementations sited here (also when using named instances in my example) you must be sure you never try to compare objects from different enums. For here’s a possible pitfall:
>>>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'''classEnum(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)returnEnum>>>Numbers= enum_repr(int, ONE=1, TWO=2, THREE=3)>>> repr(Numbers.ONE)'<enum ONE of type Enum(int)>'>>> str(Numbers.ONE)'1'
It’s elegant and clean looking, but it’s just a function that creates a class with the specified attributes.
With a little modification to the function, we can get it to act a little more ‘enumy’:
NOTE: I created the following examples by trying to reproduce the
behavior of pygtk’s new style ‘enums’ (like Gtk.MessageType.WARNING)
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
This creates an enum based off a specified type. In addition to giving attribute access like the previous function, it behaves as you would expect an Enum to with respect to types. It also inherits the base class.
Another interesting thing that can be done with this method is customize specific behavior by overriding built-in methods:
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'
The enum package from PyPI provides a robust implementation of enums. An earlier answer mentioned PEP 354; this was rejected but the proposal was implemented
http://pypi.python.org/pypi/enum.
Alexandru’s suggestion of using class constants for enums works quite well.
I also like to add a dictionary for each set of constants to lookup a human-readable string representation.
This serves two purposes: a) it provides a simple way to pretty-print your enum and b) the dictionary logically groups the constants so that you can test for membership.
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 valueassert names,'Empty enums are not supported'## enum values must be stringsassert len([i for i in names ifnot isinstance(i, types.StringTypes)andnot \
isinstance(i, unicode)])==0,'Enum values must be string or unicode'## enum values must not collide with special function namesassert 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 othersassert names == uniquify(names),'Enums must not repeat values'classEnumClass(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'] possibleif 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)classEnumValue(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 correctreturnTruedef __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
Many doctests included here to illustrate what’s different about this approach.
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
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.
回答 29
使用以下内容。
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']