Enums en Python: evita valores mágicos y errores

Actualizado el: 20/08/2026
Tempo de leitura: 4 minutos

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)  # pagado

El 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.ALTA

Los 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 = 1

Si quieres impedir duplicados, aplica @unique:

from enum import Enum, unique

@unique
class Resultado(Enum):
    CORRECTO = 1
    ERROR = 2

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

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Configuración TOML en un proyecto Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    tomllib en Python: lee archivos TOML

    Aprende a leer TOML con tomllib en Python, validar configuraciones, gestionar errores y organizar proyectos con pyproject.toml.

    Ler mais

    Tempo de leitura: 6 minutos
    24/07/2026
    Desarrollador monitoreando registros estructurados en Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Observabilidad en Python con structlog

    Aprende observabilidad en Python con structlog, eventos JSON, contexto, pruebas, control de volumen y recomendaciones para producción.

    Ler mais

    Tempo de leitura: 5 minutos
    24/07/2026
    Configuración segura de aplicaciones Python con Pydantic Settings
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Pydantic Settings: configuración segura

    Aprende a validar variables de entorno, organizar configuraciones y proteger secretos en proyectos Python con Pydantic Settings.

    Ler mais

    Tempo de leitura: 5 minutos
    23/07/2026
    Desenvolvedor programando em Python com Ruff para lint e formatação
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Ruff: lint y formato de código Python

    Aprende Ruff en Python para lint, formato, correcciones automáticas, pyproject.toml, VS Code y CI con una configuración práctica.

    Ler mais

    Tempo de leitura: 10 minutos
    22/07/2026
    Dicas para melhorar performance de scripts Python lentos
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    ¿Por qué Python es lento? Causas y optimización

    Descubre por qué Python puede ser lento y mejora su rendimiento con cProfile, algoritmos, sets, generadores, NumPy, caché y concurrencia.

    Ler mais

    Tempo de leitura: 5 minutos
    12/07/2026
    Leitura segura de senhas no terminal usando Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    getpass: lee contraseñas en terminal con Python

    Lee contraseñas de forma segura con getpass, valida entradas, evita logs y texto plano y almacena credenciales con hashing adecuado.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026