enum
Modules can define enumeration types with iteration and comparison capabilities. Instead of using integers or strings, it creates meaningful symbolic tokens for individual values.
Create an enumeration type
A new enumeration type uses class syntax Enum
to describe individual values by inheriting classes and adding class attributes to the class.
# enum_create.py
import enum
class BugStatus(enum.Enum):
new = 7
incomplete = 6
invalid = 5
wont_fix = 4
in_progress = 3
fix_committed = 2
fix_released = 1
print('\nMember name: {}'.format(BugStatus.wont_fix.name))
print('Member value: {}'.format(BugStatus.wont_fix.value))
Enum
Each member of is converted into an instance. Each instance has an name
attribute, the name of the attribute we define, and an value
attribute, the value we assign to the attribute.
$ python3 enum_create.py
Member name: wont_fix
Member value: 4
iterate
Iterating over an enumeration class yields each individual enumeration variable.
# enum_iterate.py
import enum
class BugStatus(enum.Enum):
new = 7
incomplete = 6
invalid = 5
wont_fix = 4
in_progress = 3
fix_committed = 2
fix_released = 1
for status in BugStatus:
print('{:15} = {}'.format(status.name, status.value))
Members are created in the same order as they are declared in the class. name
The value of sum value
does not affect this order.
$ python3 enum_iterate.py
new = 7
incomplete = 6
invalid = 5
wont_fix = 4
in_progress = 3
fix_committed = 2
fix_released = 1
Compare enumeration variables
Because the members of enum classes are not ordered, they only support object identity comparison and equality comparison.
# enum_comparison.py
import enum
class BugStatus(enum.Enum):
new = 7
incomplete = 6
invalid = 5
wont_fix = 4
in_progress = 3
fix_committed = 2
fix_released = 1
actual_state = BugStatus.wont_fix
desired_state = BugStatus.fix_released
print('Equality:',
actual_state == desired_state,
actual_state == BugStatus.wont_fix)
print('Identity:',
actual_state is desired_state,
actual_state is BugStatus.wont_fix)
print('Ordered by value:')
try:
print('\n'.join(' ' + s.name for s in sorted(BugStatus)))
except TypeError as err:
print(' Cannot sort: {}'.format(err))
Greater-than and less-than comparisons will throw TypeError
an exception.
$ python3 enum_comparison.py
Equality: False True
Identity: False True
Ordered by value:
Cannot sort: unorderable types: BugStatus() < BugStatus()
Using a IntEnum
class will make the members of the enumeration type behave more like numbers, for example, they support sorting.
# enum_intenum.py
import enum
class BugStatus(enum.IntEnum):
new = 7
incomplete = 6
invalid = 5
wont_fix = 4
in_progress = 3
fix_committed = 2
fix_released = 1
print('Ordered by value:')
print('\n'.join(' ' + s.name for s in sorted(BugStatus)))
$ python3 enum_intenum.py
Ordered by value:
fix_released
fix_committed
in_progress
wont_fix
invalid
incomplete
new
unique enumeration value
Enumeration members with the same value are treated as different alias references to the same object. Aliases also do not cause duplicate values in iterators of enum classes.
# enum_aliases.py
import enum
class BugStatus(enum.Enum):
new = 7
incomplete = 6
invalid = 5
wont_fix = 4
in_progress = 3
fix_committed = 2
fix_released = 1
by_design = 4
closed = 1
for status in BugStatus:
print('{:15} = {}'.format(status.name, status.value))
print('\nSame: by_design is wont_fix: ',
BugStatus.by_design is BugStatus.wont_fix)
print('Same: closed is fix_released: ',
BugStatus.closed is BugStatus.fix_released)
Because by_design
and closed
are aliases for other members, they don't appear when we iterate over the enumeration class. The member's name is considered the first name associated with this value.
$ python3 enum_aliases.py
new = 7
incomplete = 6
invalid = 5
wont_fix = 4
in_progress = 3
fix_committed = 2
fix_released = 1
Same: by_design is wont_fix: True
Same: closed is fix_released: True
If we need enum members to have unique values, we can give the enum class the 添加
@unique decorator.
# enum_unique_enforce.py
import enum
@enum.unique
class BugStatus(enum.Enum):
new = 7
incomplete = 6
invalid = 5
wont_fix = 4
in_progress = 3
fix_committed = 2
fix_released = 1
# This will trigger an error with unique applied.
by_design = 4
closed = 1
When the enum class is interpreted, an exception will be thrown if a member has a duplicate value ValueError
.
$ python3 enum_unique_enforce.py
Traceback (most recent call last):
File "enum_unique_enforce.py", line 11, in <module>
class BugStatus(enum.Enum):
File ".../lib/python3.5/enum.py", line 573, in unique
(enumeration, alias_details))
ValueError: duplicate values found in <enum 'BugStatus'>:
by_design -> wont_fix, closed -> fix_released
Programmatically create an enumeration class
In some cases, it is more convenient to create enum classes programmatically rather than hard-coding them into a class. In these scenarios, enum classes allow member names and corresponding values to be passed to the class constructor.
# enum_programmatic_create.py
import enum
BugStatus = enum.Enum(
value='BugStatus',
names=('fix_released fix_committed in_progress '
'wont_fix invalid incomplete new'),
)
print('Member: {}'.format(BugStatus.new))
print('\nAll members:')
for status in BugStatus:
print('{:15} = {}'.format(status.name, status.value))
value
The parameter is the name of the enumeration class used to create the representation of the enumeration members. names
The parameter lists all members of the enum class. If a single string is passed, it will be separated by spaces or commas, and the resulting string will be used as the member name, starting with 1, and automatically assigning a value to each member.
$ python3 enum_programmatic_create.py
Member: BugStatus.new
All members:
fix_released = 1
fix_committed = 2
in_progress = 3
wont_fix = 4
invalid = 5
incomplete = 6
new = 7
For more control over names and values, names
pass a sequence of two-element tuples or a dictionary.
# enum_programmatic_mapping.py
import enum
BugStatus = enum.Enum(
value='BugStatus',
names=[
('new', 7),
('incomplete', 6),
('invalid', 5),
('wont_fix', 4),
('in_progress', 3),
('fix_committed', 2),
('fix_released', 1),
],
)
print('All members:')
for status in BugStatus:
print('{:15} = {}'.format(status.name, status.value))
In this example names
, instead of a string containing just the member's name, we pass the parameter a list of tuples with two elements. In this way, we can create enum_create.py
the enumeration class in the same order as in the middle.
$ python3 enum_programmatic_mapping.py
All members:
new = 7
incomplete = 6
invalid = 5
wont_fix = 4
in_progress = 3
fix_committed = 2
fix_released = 1
non-integer member value
Enumeration member values are not strictly limited to integers. In fact, enum members can be any type of value. If the value is a tuple, the members are passed to the __init__()
method as private variables.
# enum_tuple_values.py
import enum
class BugStatus(enum.Enum):
new = (7, ['incomplete',
'invalid',
'wont_fix',
'in_progress'])
incomplete = (6, ['new', 'wont_fix'])
invalid = (5, ['new'])
wont_fix = (4, ['new'])
in_progress = (3, ['new', 'fix_committed'])
fix_committed = (2, ['in_progress', 'fix_released'])
fix_released = (1, ['new'])
def __init__(self, num, transitions):
self.num = num
self.transitions = transitions
def can_transition(self, new_state):
return new_state.name in self.transitions
print('Name:', BugStatus.in_progress)
print('Value:', BugStatus.in_progress.value)
print('Custom attribute:', BugStatus.in_progress.transitions)
print('Using attribute:',
BugStatus.in_progress.can_transition(BugStatus.new))
In this example, each member value is a tuple containing a numeric ID number and a list of states to which the current state can transition.
$ python3 enum_tuple_values.py
Name: BugStatus.in_progress
Value: (3, ['new', 'fix_committed'])
Custom attribute: ['new', 'fix_committed']
Using attribute: True
For more complex cases, using tuples becomes a bit unwieldy. Because member values can be objects of any type, we can use dictionaries to identify the properties scattered within each member value. The complex member value is passed directly to the method as self
the only parameter other than the parameter .__init__()
# enum_complex_values.py
import enum
class BugStatus(enum.Enum):
new = {
'num': 7,
'transitions': [
'incomplete',
'invalid',
'wont_fix',
'in_progress',
],
}
incomplete = {
'num': 6,
'transitions': ['new', 'wont_fix'],
}
invalid = {
'num': 5,
'transitions': ['new'],
}
wont_fix = {
'num': 4,
'transitions': ['new'],
}
in_progress = {
'num': 3,
'transitions': ['new', 'fix_committed'],
}
fix_committed = {
'num': 2,
'transitions': ['in_progress', 'fix_released'],
}
fix_released = {
'num': 1,
'transitions': ['new'],
}
def __init__(self, vals):
self.num = vals['num']
self.transitions = vals['transitions']
def can_transition(self, new_state):
return new_state.name in self.transitions
print('Name:', BugStatus.in_progress)
print('Value:', BugStatus.in_progress.value)
print('Custom attribute:', BugStatus.in_progress.transitions)
print('Using attribute:',
BugStatus.in_progress.can_transition(BugStatus.new))
This example uses dictionaries instead of tuples, but has the same output as the previous example.
$ python3 enum_complex_values.py
Name: BugStatus.in_progress
Value: {'transitions': ['new', 'fix_committed'], 'num': 3}
Custom attribute: ['new', 'fix_committed']
Using attribute: True
refer to:
1. Official documentation of the enum module
2. PEP 435 - Add enumeration types to the Python standard library.
3. flufl.enum -
enum
Original inspiration by Barry Warsaw