Enums en Python: evita valores mágicos y errores

Publicado el: 11/07/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

    Medição de tempo de execução de código Python com timeit
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    timeit en Python: mide el rendimiento correctamente

    Aprende timeit en Python para medir funciones, usar repeat y Timer, comparar implementaciones, reducir ruido y evitar benchmarks engañosos.

    Ler mais

    Tempo de leitura: 6 minutos
    11/07/2026
    Uso de dataclasses para simplificar classes em Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Dataclasses en Python: clases de datos más limpias

    Aprende dataclasses en Python: campos, valores predeterminados, field, frozen, order, __post_init__, herencia, asdict y buenas prácticas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Criação de hashes seguros para senhas usando Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Hash de contraseñas con bcrypt en Python

    Aprende bcrypt en Python para almacenar contraseñas: salt, coste, hash, verificación, rehash, límites, errores y recomendaciones de seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Problemas de travamento com threading em scripts Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Threading en Python: evita que tus scripts se bloqueen

    Aprende threading en Python: hilos, tareas de entrada y salida, join, locks, colas, ThreadPoolExecutor, errores y límites del GIL.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Dicas para otimizar scripts Python lentos
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Por qué tu script Python es lento y cómo mejorarlo

    Descubre por qué un script Python es lento y cómo mejorarlo con cProfile, timeit, estructuras correctas, generadores y mejores algoritmos.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Leitura de variáveis de ambiente em projetos Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Variables de entorno en Python: guía segura

    Aprende a usar variables de entorno en Python, archivos .env, validación, conversión de tipos, secretos, pruebas y buenas prácticas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026