Un enum, abreviatura de enumeración, representa un conjunto cerrado de opciones con nombres significativos. En lugar de dispersar cadenas como "pendiente", "pagado" y "cancelado" por todo el programa, puedes declarar una clase que centralice los estados válidos. Esto reduce errores de escritura, mejora el autocompletado y hace que las condiciones sean más fáciles de entender.
Los enums funcionan especialmente bien junto con la programación orientada a objetos, las funciones en Python, el manejo de excepciones y las reglas de alcance de variables.
Crear un Enum básico
from enum import Enum
class EstadoPedido(Enum):
PENDIENTE = "pendiente"
PAGADO = "pagado"
ENVIADO = "enviado"
CANCELADO = "cancelado"Cada miembro tiene un nombre y un valor:
estado = EstadoPedido.PAGADO
print(estado.name) # PAGADO
print(estado.value) # pagadoEl miembro completo es EstadoPedido.PAGADO. No es una cadena, aunque su valor asociado sí lo sea.
Comparar miembros correctamente
if estado is EstadoPedido.PAGADO:
print("El pago fue confirmado")Los miembros de un enum son únicos, por lo que is resulta apropiado. También puedes utilizar ==. Evita comparar directamente con la cadena:
# Evitar
if estado == "pagado":
...Si recibes texto externo, conviértelo primero al enum.
Convertir un valor a Enum
valor_recibido = "enviado"
try:
estado = EstadoPedido(valor_recibido)
except ValueError:
print("Estado no válido")La conversión valida automáticamente que el valor pertenezca al conjunto. Esta característica es útil al procesar JSON, formularios o filas de una base de datos.
Acceder por nombre
Si recibes el nombre en mayúsculas, utiliza la sintaxis de índice:
estado = EstadoPedido["PENDIENTE"]Un nombre inexistente lanza KeyError, mientras que un valor inexistente en la llamada EstadoPedido(valor) lanza ValueError. Captura la excepción adecuada.
Recorrer todos los miembros
for estado in EstadoPedido:
print(estado.name, estado.value)Esto permite llenar menús, generar documentación o validar configuraciones sin repetir opciones manualmente.
Evitar valores mágicos
Un valor mágico es una cadena o número cuyo significado depende del contexto:
if nivel == 3:
activar_permisos()El número tres no explica nada. Un enum mejora la intención:
from enum import IntEnum
class NivelAcceso(IntEnum):
INVITADO = 1
USUARIO = 2
ADMINISTRADOR = 3
if nivel is NivelAcceso.ADMINISTRADOR:
activar_permisos()Aunque IntEnum se comporta como entero en muchas operaciones, no abuses de esa compatibilidad. El objetivo principal sigue siendo expresar dominio y restringir valores.
Enum con auto()
Cuando el valor concreto no importa, auto() evita asignarlo manualmente:
from enum import Enum, auto
class Direccion(Enum):
NORTE = auto()
SUR = auto()
ESTE = auto()
OESTE = auto()No dependas de los números generados como parte de una API persistente. Si vas a almacenar valores en una base de datos o enviarlos por red, define valores explícitos y estables.
String enums modernos
Las versiones recientes de Python ofrecen StrEnum, cuyos miembros se comportan como cadenas:
from enum import StrEnum
class Formato(StrEnum):
JSON = "json"
CSV = "csv"
XML = "xml"
print(Formato.JSON.upper())Esto facilita la integración con librerías que esperan texto, pero sigue siendo recomendable convertir de forma explícita en los límites de la aplicación.
Añadir métodos al Enum
Un enum puede incluir comportamiento:
from enum import Enum
class Prioridad(Enum):
BAJA = 1
MEDIA = 2
ALTA = 3
def requiere_alerta(self) -> bool:
return self is Prioridad.ALTALos métodos relacionados directamente con los valores válidos pueden vivir en la clase. Evita convertir el enum en una clase enorme con lógica de negocio no relacionada.
Propiedades y etiquetas legibles
class EstadoUsuario(Enum):
ACTIVO = "active"
BLOQUEADO = "blocked"
@property
def etiqueta(self):
etiquetas = {
EstadoUsuario.ACTIVO: "Activo",
EstadoUsuario.BLOQUEADO: "Bloqueado",
}
return etiquetas[self]Para sistemas multilingües, suele ser mejor mantener las traducciones fuera del enum y usar sus valores como claves estables.
Alias y valores duplicados
Por defecto, dos nombres pueden compartir un valor, creando un alias:
class Resultado(Enum):
CORRECTO = 1
EXITOSO = 1Si quieres impedir duplicados, aplica @unique:
from enum import Enum, unique
@unique
class Resultado(Enum):
CORRECTO = 1
ERROR = 2Un valor repetido provocará una excepción al definir la clase, lo cual detecta el problema temprano.
Flags combinables
Flag e IntFlag representan opciones que pueden combinarse:
from enum import Flag, auto
class Permiso(Flag):
LEER = auto()
ESCRIBIR = auto()
ELIMINAR = auto()
permisos = Permiso.LEER | Permiso.ESCRIBIR
if Permiso.ESCRIBIR in permisos:
print("Puede escribir")Este patrón es útil para capacidades, modos o características independientes. Si las opciones son mutuamente excluyentes, utiliza un Enum normal.
Serializar enums a JSON
El módulo json no serializa cualquier Enum automáticamente. Convierte a value:
import json
datos = {
"pedido": 123,
"estado": EstadoPedido.ENVIADO.value,
}
texto = json.dumps(datos, ensure_ascii=False)Al leer el JSON, reconstruye el enum y captura ValueError. Esta validación impide que estados desconocidos circulen dentro del dominio.
Enums y bases de datos
Decide si guardarás el nombre o el valor. Los nombres son legibles, pero cambiar un identificador puede requerir una migración. Los valores explícitos pueden mantenerse estables aunque cambie la etiqueta mostrada. Documenta la estrategia y no almacenes el resultado de auto() si puede variar.
Cuándo no usar Enum
No uses un enum para listas que cambian frecuentemente o que los administradores deben editar sin desplegar código. Países, productos o categorías de negocio suelen pertenecer a una base de datos. Un enum es ideal cuando el conjunto es pequeño, conocido y controlado por la aplicación.
La documentación oficial del módulo enum describe Enum, IntEnum, StrEnum, Flag y sus reglas. La PEP 435 explica el diseño y la incorporación de enumeraciones a Python.
Errores frecuentes
Los problemas más comunes son comparar el miembro con una cadena, almacenar valores generados con auto() sin estabilidad, usar IntEnum solo para aprovechar operaciones numéricas, permitir alias accidentales y convertir a Enum sin manejar entradas inválidas. También es un error utilizar enums para datos dinámicos que deberían administrarse externamente.
Conclusión
Los enums convierten valores dispersos en un modelo explícito y validado. Mejoran la lectura, reducen errores tipográficos y centralizan los estados permitidos. Elige Enum para opciones exclusivas, StrEnum cuando la integración textual sea importante y Flag para capacidades combinables. Con valores estables y conversiones en los límites de la aplicación, los enums hacen que el código sea más seguro y fácil de mantener.






