dataclasses
dataclasses (stdlib desde 3.7) genera el código repetitivo de métodos comunes para clases que principalmente contienen datos. Son la opción predeterminada para registros internos antes de recurrir a modelos ORM completos.
Receta
from dataclasses import dataclass, field
@dataclass
class User:
id: int
name: str
tags: list[str] = field(default_factory=list)Cuándo usar esto:
- Eventos de dominio y DTOs dentro de las capas de aplicación
- Objetos de configuración/valor inmutables (
frozen=True) - Estructuras anidadas con
__repr__legible para depuración - Reemplazar tuplas donde los nombres de campo ayudan a la legibilidad
Ejemplo de Trabajo
from dataclasses import dataclass, field
@dataclass(frozen=True)
class Money:
amount: int
currency: str
def __post_init__(self) -> None:
if self.amount < 0:
raise ValueError("amount must be non-negative")
@dataclass
class Order:
id: int
lines: list[Money] = field(default_factory=list)
def total(self) -> Money:
if not self.lines:
return Money(0, "USD")
currency = self.lines[0].currency
amount = sum(line.amount for line in self.lines)
return Money(amount, currency)
if __name__ == "__main__":
order = Order(1, [Money(100, "USD"), Money(50, "USD")])
print(order)
print(order.total())Lo que esto demuestra:
frozen=Trueevita la reasignación de atributos después de la creación__post_init__valida invariantes después de__init__default_factory=listcrea una lista nueva por instancia- Los métodos coexisten con los métodos generados por dataclass
Análisis Profundo
Cómo Funciona
- El decorador transforma la clase - Añade métodos basados en campos y banderas en el momento de la creación de la clase.
- Orden de los campos - Los campos sin valores predeterminados deben preceder a los campos con valores predeterminados.
- KW_ONLY -
field(kw_only=True)fuerza el paso por palabra clave para campos tardíos (3.10+). - slots -
@dataclass(slots=True)combina dataclass con__slots__(3.10+). - replace -
dataclasses.replace(obj, amount=200)actualizaciones funcionales en instancias congeladas.
Banderas Útiles
| Bandera | Efecto |
|---|---|
frozen=True | Inmutable + hasheable (si los campos son hasheables) |
order=True | Genera comparaciones de ordenación |
slots=True | Instancias eficientes en memoria |
kw_only=True | Todos los campos solo por palabra clave (3.10+) |
Notas de Python
from dataclasses import asdict, astuple
payload = asdict(order) # diccionario superficial - los dataclasses anidados se recursan
coords = astuple(point)Errores Comunes
- Lista predeterminada mutable -
tags: list = []sigue siendo un error sinfield. Solución:field(default_factory=list). - Orden de campos en herencia - Los valores predeterminados de las subclases son complicados a través del MRO. Solución: Mantener jerarquías poco profundas o usar composición.
asdictcon mutables profundos - Copia la estructura pero los mutables anidados aún se aliastan si no son dataclasses. Solución: Conocer las necesidades superficiales vs. profundas.frozencon campos mutables -frozenevita la reasignación delinespero la lista interna sigue siendo mutable. Solución: Campos de tupla o tipos inmutables.- Comparación con
dict- La instancia de dataclass no es igual adictaunque los campos coincidan. Solución: Convertir explícitamente para APIs JSON.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
NamedTuple | Similar a tupla inmutable | Necesita mutabilidad |
TypedDict | Forma de diccionario JSON | Necesita métodos/validación |
Pydantic BaseModel | Validación HTTP | Dominio interno sin E/S |
| clase simple | Ciclo de vida complejo | Código repetitivo de registro simple |
Preguntas Frecuentes
¿dataclass vs NamedTuple?
dataclass ofrece mutabilidad y métodos flexibles. NamedTuple es una subclase de tupla inmutable más ligera.
¿Cómo validar campos?
__post_init__ o una capa externa de Pydantic en los límites. Los dataclasses no validan tipos automáticamente en tiempo de ejecución.
¿Puedo personalizar __init__?
Sí, pero a menudo es innecesario; usa __post_init__ en su lugar para mantener el init generado.
¿frozen y hasheable?
Los dataclasses frozen son hasheables cuando todos los campos son hasheables; genial para claves de diccionario.
¿field(default=...) vs default_factory?
default para valores predeterminados inmutables (int, str, None). default_factory para crear un nuevo objeto mutable cada vez.
¿Vale la pena slots=True?
Millones de instancias: ahorra memoria. Pocas instancias: omite la complejidad.
¿Herencia con dataclasses?
Soportado; ten cuidado con el orden de los campos y los valores predeterminados entre padre/hijo.
¿asdict para JSON?
Útil para serialización simple; ten en cuenta que tipos personalizados como datetime/decimal necesitan un codificador personalizado.
¿kw_only en un solo campo?
Fuerza el uso de palabra clave para ese campo al crear una instancia; APIs más claras con muchos parámetros.
¿dataclass vs attrs?
Quédate con la biblioteca estándar a menos que las características de attrs (validadores, conversores) ya sean estándar en tu organización.
Relacionado
- Dunder / Magic Methods - métodos generados
- Properties & Descriptors - campos calculados
- TypedDict & NamedTuple - alternativas de tipado
- Immutability & Hashability - objetos congelados
Versiones de Stack: Esta página fue escrita 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+.