dataclasses, enum y contextlib
dataclasses reduce el código repetitivo para objetos de datos. enum proporciona constantes con nombre con seguridad de tipos. contextlib simplifica los gestores de contexto (contextmanager, suppress, ExitStack).
Receta
from dataclasses import dataclass
from enum import StrEnum
from contextlib import contextmanager
class Status(StrEnum):
PENDING = "pending"
DONE = "done"
@dataclass(frozen=True)
class Job:
id: int
status: Status = Status.PENDINGCuándo usar esto:
- DTOs y registros de configuración ->
dataclass - Constantes de modo/estado ->
StrEnum - Ámbitos rápidos de recursos ->
@contextmanager - Archivo opcional ausente ->
suppress(FileNotFoundError) - Muchos gestores anidados ->
ExitStack
Ejemplo de funcionamiento
from contextlib import contextmanager, suppress
from dataclasses import dataclass, field
from enum import StrEnum
class Role(StrEnum):
ADMIN = "admin"
USER = "user"
@dataclass
class Account:
email: str
role: Role = Role.USER
tags: list[str] = field(default_factory=list)
@contextmanager
def temp_role(account: Account, role: Role):
old = account.role
account.role = role
try:
yield account
finally:
account.role = old
ada = Account("ada@example.com")
with temp_role(ada, Role.ADMIN):
print("elevated", ada.role)
print("restored", ada.role)
with suppress(FileNotFoundError):
open("missing.cfg").read()Lo que esto demuestra:
frozen=Truepara objetos de valor inmutablesfield(default_factory=list)evita el error común de valores predeterminados mutablesStrEnumse serializa limpiamente a cadenas JSONcontextmanagerpara estados temporales reversibles
Inmersión Profunda
Opciones de dataclass
slots=True(3.10+) ahorra memoriakw_only=True(3.10+) construcción explícita__post_init__para validación
Sabores de enum
StrEnumpara APIs JSONIntEnumpara códigos numéricos- Decorador
@uniquepara evitar duplicados de alias
Errores comunes
dataclassmutable como clave de diccionario - no se puede hashear a menos que seafrozen. Solución:frozen=Trueo no usar la instancia como clave.- Comparación de
enumcon cadena sin formato -StrEnumcompara igual constren 3.11+, pero sé explícito en las APIs. Solución: usarRolecomo tipo de dato, nostr. contextmanagersintry/finally- la limpieza se omite en caso de error. Solución: envolveryieldentry/finally.ExitStackolvidado - errores de cierre manual. Solución: usar siemprewith ExitStack().dataclassvs Pydantic -dataclassno tiene validación. Solución: Pydantic en el límite HTTP.
Alternativas
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
| Pydantic BaseModel | Validación/coerción | DTO de bucle interno rápido |
| TypedDict | Diccionarios con forma JSON | Se necesitan métodos |
| attrs | Ecosistema de attrs | Solo biblioteca estándar |
Preguntas frecuentes
¿`dataclass` vs `namedtuple`?
dataclass ofrece valores predeterminados flexibles y control de mutabilidad.
¿`auto()` en enums?
Enum.auto() asigna valores automáticamente para StrEnum no numéricos.
¿`contextlib.closing`?
Envuelve objetos que se pueden cerrar (close()) pero que no son gestores de contexto.
¿`asynccontextmanager`?
Contraparte asíncrona en contextlib para bloques async with.
¿`field(repr=False)`?
Oculta campos sensibles de la salida repr.
¿Memoria con `slots`?
Medible en recuentos de instancias muy grandes: perfila antes de usar slots por defecto en todas partes.
¿Serializar `enum` a JSON?
El .value de StrEnum es una cadena (str) - json.dumps lo maneja en los valores del diccionario.
¿`match` con `enum`?
La coincidencia de patrones estructural funciona con miembros de enum en 3.10+.
¿Probar contextos temporales?
Verifica el estado antes y después de que se eleve el bloque with.
¿Opciones de Django?
TextChoices/IntegerChoices reflejan el patrón enum en Django 5.2.
Relacionado
- Context Managers as a Pattern - profundidad del patrón
- json & Serialization -
StrEnumen JSON - collections recap -
Countercon enums - Standard Library Best Practices - reglas ergonómicas
Versiones de la pila: Esta página se escribió para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.