enum – Tipo de Enumeración¶
El módulo enum
define un tipo de enumeración con capacidades de iteración y
comparación. Puede ser usado para creae símbolos bien definidos para valores,
en lugar de usar enteros literales o cadenas.
Creando enumeraciones¶
Una nueva enumeración se define utilizando la sintaxis class
creando una
subclase de Enum
y agregando atributos de clase que describen los valores.
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))
Los miembros del Enum
se convierten en instancias cuando la clase es
analizada. Cada instancia tiene una propiedad name
que correspondiente al
nombre del miembro y una propiedad value
correspondiente al valorasignado
al nombre en la definición de la clase.
$ python3 enum_create.py
Member name: wont_fix
Member value: 4
Iteración¶
Iterar sobre la clase emun produce los miembros individuales de la enumeración.
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))
Los miembros se producen en el orden en que se declaran en la definición de la clase. Los nombres y valores no se usan para ordenarlos de ninguna manera.
$ python3 enum_iterate.py
new = 7
incomplete = 6
invalid = 5
wont_fix = 4
in_progress = 3
fix_committed = 2
fix_released = 1
Comparando Enums¶
Como los miembros de la enumeración no están ordenados, solo admiten comparación por identidad e igualdad.
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))
Los operadores de comparación mayor que y menor que elevan excepciones
TypeError
.
$ python3 enum_comparison.py
Equality: False True
Identity: False True
Ordered by value:
Cannot sort: unorderable types: BugStatus() < BugStatus()
Usa la clase IntEnum
para enumeraciones donde los miembros necesitan
comportarse más como números — por ejemplo, para ofrecer comparaciones.
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
Valore de enumeración únicos¶
Los miembros de Enum con el mismo valor se tratan como referencias de alias al
mismo objeto miembro. Los alias no hacen que los valores repetidos esten
presentes en el iterador para el Enum
.
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)
Porque by_design
y closed
son alias para otros miembros, no aparecen
por separado en el resultado al iterar sobre el Enum
. El nombre canónico
para un miembro es el primer nombre unido al valor.
$ 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
Para requerir que todos los miembros tengan valores únicos, agregue el
decorador @unique
al Enum
.
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
Los miembros con valores repetidos elevan una excepción ValueError
cuando
la clase Enum
está siendo interpretada.
$ 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
Creando enumeraciones programáticamente¶
En algunos casos, es más conveniente crear enumeraciones programáticamente, en
lugar de codificarlos en una definició de nclase. Para esas situaciones,
Enum
también admite pasar los nombres y valores de los miembros al
constructor de la clase.
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))
El argumento value
es el nombre de la enumeración, que se usa para compilar
la representación de los miembros. El argumento names
lista los miembros
de la enumeración. Cuando se pasa una sola cadena, es dividida en espacios en
blanco y comas, y los tokens resultantes se utilizan como nombres para los
miembros, que son valores asignados automáticamente comenzando con 1
.
$ 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
Para un mayor control sobre los valores asociados con los miembros, la cadena
names
se puede reemplazar por una secuencia de tuplas de dos partes o un
diccionario mapeando nombres a valores.
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))
En este ejemplo, se proporciona una lista de tuplas de dos partes en lugar de
una sola cadena que contiene solo los nombres de los miembros. Esto hace
posible reconstruir la enumeración BugStatus
con los miembros en el mismo
orden como la versión definida en enum_create.py
.
$ 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
Valores miembros no enteros¶
Los valores de miembro de Enum no están restringidos a enteros. De hecho,
cualquier tipo de objeto se puede asociar con un miembro. Si el valor es una
tupla, los miembros se pasan como argumentos individuales a __init __()
.
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))
En este ejemplo, cada valor de miembro es una tupla que contiene el ID numérico (tal como podría estar almacenado en una base de datos) y una lista de transiciones a partir del estado actual.
$ python3 enum_tuple_values.py
Name: BugStatus.in_progress
Value: (3, ['new', 'fix_committed'])
Custom attribute: ['new', 'fix_committed']
Using attribute: True
Para casos más complejos, las tuplas pueden volverse difíciles de manejar.
Como cualquier tipo de objeto puede ser valor miembro, los diccionarios se
pueden usar para los casos donde hay muchos atributos separados para seguir por
cada valor enum. Los valores complejos se pasan directamente a __init__()
como único argumento que no sea self
.
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))
Este ejemplo expresa los mismos datos que el ejemplo anterior, utilizando diccionarios en lugar de tuplas.
$ python3 enum_complex_values.py
Name: BugStatus.in_progress
Value: {'transitions': ['new', 'fix_committed'], 'num': 3}
Custom attribute: ['new', 'fix_committed']
Using attribute: True
Ver también
- Documentación de la biblioteca estándar para enum
- PEP 435 – Agregar un tipo Enum a la biblioteca estándar de Python
- flufl.enum – La inspiración
original para
enum
, por Barry Warsaw.