Python Módulo 9 – Python orientado a objetos y el modelo de datos
Dataclasses para objetos de datos limpios
Escribe dataclasses de Python con valores por defecto y fábricas, valida en __post_init__, usa frozen, order, slots y kw_only, y compáralas con pydantic.
Qué vas a aprender
- Definir dataclasses con valores por defecto, fábricas por defecto y valores calculados
- Usar las opciones frozen, order, slots y kw_only y predecir lo que escribe cada una
- Validar y derivar campos en __post_init__, y copiar objetos con replace()
- Elegir entre una dataclass, una NamedTuple, attrs y pydantic para una tarea
- Reconocer las trampas de las dataclasses en la igualdad, el hash, el orden de los campos y las copias superficiales
Antes de empezar
Qué vas a aprender · Antes de empezar
Qué vas a aprender
- Definir dataclasses con valores por defecto, fábricas por defecto y valores calculados
- Usar las opciones frozen, order, slots y kw_only y predecir lo que escribe cada una
- Validar y derivar campos en __post_init__, y copiar objetos con replace()
- Elegir entre una dataclass, una NamedTuple, attrs y pydantic para una tarea
- Reconocer las trampas de las dataclasses en la igualdad, el hash, el orden de los campos y las copias superficiales
Antes de empezar
En esta página
Un artículo de un pedido con tres campos necesita tres métodos escritos a mano antes de ser útil: un __init__ que guarda los campos, un __repr__ que los muestra y un __eq__ que los compara. Una dataclass: Una clase decorada con @dataclass. El decorador escribe su __init__, su __repr__ y su __eq__ a partir de los campos anotados en su cuerpo, como name: str y quantity: int = 1, y opciones como frozen=True u order=True añaden más. es una clase normal cuyos métodos aburridos escribe Python por ti. Pon @dataclass encima de una clase cuyo cuerpo enumera sus campo de una dataclass: Una línea con una anotación de tipo en el cuerpo de una dataclass, como quantity: int = 1. Su nombre pasa a ser un parámetro del __init__ escrito, con su valor por defecto si lo tiene; field() añade opciones como default_factory o compare=False. con anotaciones de tipo, como name: str y quantity: int = 1, y el decorador de clase: Un decorador escrito encima de una sentencia class. Recibe la clase cuando ya se ha ejecutado el cuerpo de la clase, y el nombre de la clase se enlaza a lo que devuelve, normalmente la misma clase, cambiada. Más en “Decoradores: envolver funciones con limpieza” (en inglés) escribe los tres a partir de ellos.
Las opciones cambian lo que escribe: frozen=True hace que los objetos sean inmutables y hashables, order=True añade <, <=, > y >=, slots=True añade __slots__: Un atributo de clase que enumera los nombres de los atributos de instancia, como __slots__ = ("x", "y"). Los objetos de la clase reciben un sitio fijo por nombre y ningún __dict__, así que ocupan menos memoria y rechazan cualquier otro nombre de atributo. Más en “__slots__, referencias débiles y ciclo de vida de los objetos” (en inglés) y kw_only=True convierte cada campo en un argumento con nombre. Un valor por defecto mutable, como una lista, necesita field(default_factory=list), y __post_init__ se ejecuta después de __init__ para validar o derivar valores. Las dataclasses van bien para los registros que son sobre todo datos, como pedidos, reservas, ajustes y mensajes, mientras que las clases con un comportamiento rico siguen mereciendo métodos escritos a mano. A continuación construyes un pedido con sus artículos, te encuentras con el error del valor por defecto mutable y pruebas todas las opciones.
El decorador escribe tres métodos a partir de los campos anotados
import inspect
from dataclasses import dataclass, field, fields
@dataclass
class OrderItem:
name: str
unit_paise: int
quantity: int = 1
@property
def total_paise(self):
return self.unit_paise * self.quantity
@dataclass
class Order:
number: int
items: list[OrderItem] = field(default_factory=list)
def total_paise(self):
return sum(item.total_paise for item in self.items)
order = Order(1042, [OrderItem("masala dosa", 9000, 2), OrderItem("filter coffee", 4000)])
print(order)
print("total:", order.total_paise(), "| equal to a copy:", order == Order(1042, list(order.items)))
print("generated __init__:", inspect.signature(OrderItem))
print("fields:", [(f.name, f.type) for f in fields(OrderItem)]) Salida
Order(number=1042, items=[OrderItem(name='masala dosa', unit_paise=9000, quantity=2), OrderItem(name='filter coffee', unit_paise=4000, quantity=1)])
total: 22000 | equal to a copy: True
generated __init__: (name: str, unit_paise: int, quantity: int = 1) -> None
fields: [('name', <class 'str'>), ('unit_paise', <class 'int'>), ('quantity', <class 'int'>)]
Salida registrada con Python 3.14.8 en macOS 26 arm64. Para ejecutarlo tú: mise exec python@3.14.8 -- python3 order_items.py
Se ejecuta en este dispositivo, en tu navegador. La primera ejecución descarga Python (unos 13.5 MB), que se guarda para las siguientes.
Tu ejecución, en este navegador
Lo que escribe @dataclass a partir del cuerpo de una clase
Descripción en texto del diagrama
El diagrama es un flujo de arriba abajo.
- Arriba hay un cuerpo de clase con tres campos anotados: name de tipo str, unit_paise de tipo int y quantity de tipo int con el valor por defecto 1.
- El decorador @dataclass lee las anotaciones en orden.
- Escribe tres métodos: __init__, con un parámetro por campo y el valor por defecto de quantity; __repr__, que muestra cada campo por su nombre; y __eq__, que compara campo a campo dos objetos de la misma clase.
- Las opciones cambian lo que se escribe: order=True añade las cuatro comparaciones de orden, frozen=True rechaza la asignación y añade __hash__, slots=True añade __slots__ y kw_only=True hace que los parámetros de __init__ sean solo por nombre.
- Los campos salen de las anotaciones, en orden, como muestra el diagrama, y
quantity: int = 1pasó a ser un valor por defecto de__init__, como muestra la firma generada. - El repr nombra cada campo, incluidas las dataclasses anidadas, lo que hace legibles los registros y los fallos de las pruebas.
- Dos pedidos con campos iguales son iguales.
__eq__compara campo a campo, y solo objetos de la misma clase. - Los métodos y las propiedades se escriben como en cualquier clase:
total_paisees una propiedad de un artículo ytotal_paise()un método del pedido.fields()enumera los campos con sus tipos, para el código que trabaja con cualquier dataclass.
Recorre las llamadas que hace el programa a los métodos escritos:
El dibujo muestra la escena completa; sus 6 pasos aparecen abajo.
Todos los pasos en texto
- El primer artículo. OrderItem("masala dosa", 9000, 2) invoca el __init__ escrito, cuyos parámetros son los campos en el orden de las anotaciones: name, unit_paise, quantity.
- Campos guardados. __init__ asigna cada argumento a su campo, así que el artículo contiene name, unit_paise y quantity, y su propiedad total_paise da 18000.
- Un valor por defecto. OrderItem("filter coffee", 4000) deja fuera quantity, así que __init__ usa el valor por defecto del cuerpo de la clase, 1.
- El repr. print(order) invoca el __repr__ escrito, que muestra cada campo por su nombre, incluidos los artículos que contiene, porque una lista muestra el repr de cada elemento.
- Iguales por sus campos. order == Order(1042, list(order.items)) invoca el __eq__ escrito. Los dos son Order, los números son iguales y las dos listas contienen los mismos artículos, así que la respuesta es True.
- La firma. inspect.signature(OrderItem) muestra el __init__ que se escribió, (name, unit_paise, quantity = 1), con los tipos copiados de las anotaciones; nada los comprueba cuando se ejecuta el programa.
Las anotaciones no se comprueban cuando se ejecuta el programa: OrderItem("tea", "forty") se acepta, porque los tipos son para los lectores y para los comprobadores de tipos. Las comprobaciones que tienen que ejecutarse van en __post_init__.
Punto de control
Comprueba: lo que escribe @dataclass
Un valor por defecto de lista se rechaza, y una fábrica da a cada objeto el suyo
from dataclasses import dataclass, field
try:
@dataclass
class Cart:
items: list = [] # one list for every cart, so dataclasses refuses it
except ValueError as error:
print("ValueError:", error)
@dataclass
class Cart:
items: list = field(default_factory=list) # a new list for every cart
first, second = Cart(), Cart()
first.items.append("tea")
print(first, second, first.items is second.items)
try:
@dataclass
class Ticket:
coach: str = "S1"
seat: int # a field without a default after one with a default
except TypeError as error:
print("TypeError:", error) Salida
ValueError: mutable default <class 'list'> for field items is not allowed: use default_factory Cart(items=['tea']) Cart(items=[]) False TypeError: non-default argument 'seat' follows default argument 'coach'
Salida registrada con Python 3.14.8 en macOS 26 arm64. Para ejecutarlo tú: mise exec python@3.14.8 -- python3 defaults.py
Se ejecuta en este dispositivo, en tu navegador. La primera ejecución descarga Python (unos 13.5 MB), que se guarda para las siguientes.
Tu ejecución, en este navegador
Un valor por defecto se evalúa una vez, cuando se define la clase, así que una lista escrita como valor por defecto sería una sola lista compartida por todos los carritos. Las dataclasses la rechazan en el acto con ValueError y nombran el arreglo: field(default_factory=list) invoca list() para cada objeto nuevo, así que los dos carritos tienen listas separadas. Recorre los carritos y las listas que contienen:
El dibujo muestra la escena completa; sus 5 pasos aparecen abajo.
Todos los pasos en texto
- Una lista como valor por defecto. Un valor por defecto se evalúa una vez, cuando se define la clase, así que items = [] sería una sola lista compartida por todos los carritos. El decorador lo rechaza con ValueError y nombra el arreglo, default_factory.
- Una fábrica en su lugar. field(default_factory=list) guarda la función list. El __init__ escrito la invoca para cada carrito nuevo, así que first recibe una lista propia.
- Un segundo carrito. second = Cart() vuelve a llamar a list(), así que su campo items se refiere a una lista distinta.
- Añadir a uno. first.items.append("tea") cambia solo la lista de first, así que el programa imprime Cart(items=['tea']) y Cart(items=[]), y first.items is second.items es False.
- El orden de los campos. Los campos pasan a ser los parámetros de __init__, así que un campo sin valor por defecto después de uno con valor por defecto, seat después de coach = "S1", falla con TypeError, como fallaría en cualquier def.
Desde Python 3.11 el decorador rechaza cualquier valor por defecto no hashable, diccionarios y conjuntos incluidos, porque un valor no hashable probablemente es mutable. Un valor por defecto hashable se sigue evaluando una sola vez, así que un valor que tenga que ser nuevo para cada objeto viene de una La función que guarda field(default_factory=…). El __init__ escrito la invoca sin argumentos para cada objeto nuevo, así que cada objeto recibe un valor nuevo, como una lista vacía propia.. El orden de los campos también importa, porque los campos pasan a ser los parámetros de __init__: un campo sin valor por defecto no puede ir después de uno con valor por defecto, como en cualquier función de Python.
Punto de control
Comprueba: valores por defecto y fábricas por defecto
Cuatro opciones cambian lo que escribe el decorador
from dataclasses import FrozenInstanceError, dataclass
@dataclass(frozen=True)
class Point:
x: int
y: int
home = Point(12, 7)
visits = {home: 3}
print(visits[Point(12, 7)], hash(home) == hash(Point(12, 7)))
try:
home.x = 13
except FrozenInstanceError as error:
print("FrozenInstanceError:", error)
@dataclass(order=True)
class Release:
major: int
minor: int
patch: int = 0
print(sorted([Release(3, 14, 8), Release(3, 9), Release(3, 14)]), Release(3, 9) < Release(3, 14))
@dataclass(kw_only=True, slots=True)
class Retry:
attempts: int = 3
delay_seconds: float = 0.5
print(Retry(delay_seconds=2.0), hasattr(Retry(), "__dict__"))
try:
Retry(5)
except TypeError as error:
print("TypeError:", error) Salida
3 True FrozenInstanceError: cannot assign to field 'x' [Release(major=3, minor=9, patch=0), Release(major=3, minor=14, patch=0), Release(major=3, minor=14, patch=8)] True Retry(attempts=3, delay_seconds=2.0) False TypeError: Retry.__init__() takes 1 positional argument but 2 were given
Salida registrada con Python 3.14.8 en macOS 26 arm64. Para ejecutarlo tú: mise exec python@3.14.8 -- python3 options.py
Se ejecuta en este dispositivo, en tu navegador. La primera ejecución descarga Python (unos 13.5 MB), que se guarda para las siguientes.
Tu ejecución, en este navegador
frozen=True rechaza la asignación después de la creación, con FrozenInstanceError, y como los campos ya no pueden cambiar, el decorador también escribe un __hash__ a partir de ellos: un punto dataclass congelada: Una dataclass declarada con frozen=True. Asignar a un campo después de crear el objeto lanza FrozenInstanceError, y con el eq=True por defecto el decorador también escribe un __hash__ a partir de los campos, así que los objetos pueden ser claves de un dict. sirve como clave de un diccionario. Una dataclass normal no, porque, como cualquier clase que define __eq__ sin __hash__, no es hashable. order=True compara los objetos campo a campo, como las tuplas, así que las versiones se ordenan por major, después por minor y después por patch. Sigue las comparaciones de las versiones:
El dibujo muestra la escena completa; sus 4 pasos aparecen abajo.
Todos los pasos en texto
- Release(3, 9) < Release(3, 14). El __lt__ escrito compara los primeros campos. Los dos major son 3, así que la comparación sigue con el campo siguiente.
- Decide el minor. 9 es menor que 14, así que la respuesta es True y el patch ni se mira, como con las tuplas (3, 9, 0) y (3, 14, 0).
- 3.14.0 frente a 3.14.8. Para sorted(), los major son iguales y también los minor, 14 y 14, así que decide el patch.
- La lista ordenada. sorted() puso las tres versiones en el orden 3.9.0, 3.14.0, 3.14.8, porque cada comparación toma los campos en el orden en que se declaran.
kw_only=True hace que cada parámetro sea parámetro solo por nombre: Un parámetro después de * o *args en una firma, como key en sorted(iterable, /, *, key=None, reverse=False). Una llamada tiene que pasarlo por su nombre. Más en “Parámetros: por defecto, solo por nombre y solo por posición” (en inglés), lo que mantiene legibles las llamadas cuando una clase tiene varios ajustes del mismo tipo, y slots=True da a la clase __slots__, así que sus objetos no tienen __dict__ y usan menos memoria.
Los campos sueltos también tienen opciones. field(repr=False) deja un valor fuera del repr, lo que importa con las contraseñas y los tokens que, si no, acabarían en los registros y en los informes de errores, y field(compare=False) deja un campo fuera de la igualdad. Las dataclasses también funcionan en las sentencias match: el decorador escribe __match_args__: Un atributo de clase que contiene una tupla de nombres de atributos. Le dice a un patrón de clase qué atributo representa cada subpatrón posicional; @dataclass lo fija a los campos en el orden en que se declaran. Más en “Coincidencia estructural: listas, diccionarios y clases” (en inglés), así que case OrderItem(name, price, 1): encaja un artículo por posición. Las versiones que trajeron estas opciones:
- 3.7
El módulo dataclasses
La PEP 557 añadió @dataclass y field(), con las opciones init, repr, eq, order y frozen.
- 3.10
slots, kw_only y match_args opciones nuevas
slots=True añade __slots__ a la clase, kw_only=True hace que todos los parámetros sean solo por nombre, y match_args escribe __match_args__ para las sentencias match.
- 3.11
Valores por defecto no hashables rechazados cambiado
En lugar de rechazar solo list, dict y set, el decorador rechaza ahora cualquier valor por defecto no hashable, porque un valor no hashable probablemente es mutable.
La cronología tiene 3 momentos, de 3.7 a 3.11.
Punto de control
Comprueba: frozen, order, slots y kw_only
dataclass, NamedTuple, attrs o pydantic: ¿cuál encaja?
Tres preguntas sobre tus datos deciden casi toda la elección; respóndelas en la tabla:
Responde las preguntas de arriba: entonces la tabla marca lo que encaja con tu caso y dice por qué el resto no.
| Herramienta | Comprueba los valores al crearse | Puede cambiar después de crearse | Se desempaqueta como una tupla | Nada que instalar |
|---|---|---|---|---|
| @dataclass Viene de: la biblioteca estándar | Regular solo lo que escribas en __post_init__; las anotaciones no se comprueban | Bien sí, salvo con frozen=True | Malo no, no es iterable | Bien viene con Python |
| typing.NamedTuple (en inglés) Viene de: la biblioteca estándar | Malo no, las anotaciones no se comprueban | Malo no, es tan inmutable como cualquier tupla | Bien sí: p.x y p[0] leen el mismo campo | Bien viene con Python |
| attrs Viene de: un paquete de terceros | Regular con los validadores y conversores que añadas | Bien sí, salvo que esté congelado | Malo no, no es una tupla | Malo un paquete que instalar y mantener al día |
| pydantic Viene de: un paquete de terceros | Bien sí, y convierte: el texto "34" pasa a ser el int 34 | Bien sí, por defecto | Malo no, no es una tupla | Malo un paquete que instalar y mantener al día |
Cómo deciden las respuestas
- “¿De dónde vienen los datos?” De fuera: JSON, formularios, archivos de ajustes: descarta typing.NamedTuple y añade una advertencia a @dataclass y a attrs. Los datos de fuera hay que comprobarlos y convertirlos cuando se crea el objeto. Una dataclass solo comprueba lo que escribas en __post_init__, attrs lo que comprueben sus validadores.
- “¿De dónde vienen los datos?” Los crea mi propio código: añade una advertencia a pydantic. Ya se sabe que los datos que crea tu propio código son válidos, así que comprobarlos otra vez en cada creación cuesta tiempo para nada.
- “¿Tiene que cambiar un registro después de crearse?” Sí, sus campos se actualizan: descarta typing.NamedTuple. Una NamedTuple es inmutable, así que un registro cuyos campos se actualizan necesita otro tipo.
- “¿Puede el proyecto añadir un paquete de terceros?” No, solo la biblioteca estándar: descarta attrs y pydantic. Los dos son paquetes de terceros; la biblioteca estándar ofrece @dataclass y NamedTuple.
Una dataclass es la elección por defecto para los datos que crea tu propio código. Una tupla con nombre: Un tipo de tupla cuyas posiciones también tienen nombre, creado con typing.NamedTuple o collections.namedtuple(). p.x y p[0] leen el mismo campo, y es tan inmutable como cualquier tupla. Más en “Tuplas, desempaquetado y tuplas con nombre” (en inglés) es inmutable y se desempaqueta como una tupla, lo que va bien para valores pequeños como las coordenadas. attrs es la biblioteca de terceros que inspiró las dataclasses, con validadores, conversores y algunas opciones más. pydantic comprueba y convierte la entrada cuando se crea un objeto, que es lo que necesitan los datos de fuera.
La elección rara vez es de todo o nada. Muchos programas usan dataclasses normales por dentro, donde ya se sabe que los datos son válidos, y un modelo que valida solo en los bordes, donde llegan las peticiones, los archivos y los mensajes; asdict() convierte una dataclass en un diccionario que acepta un modelo así, o json.dumps.
Punto de control
Comprueba: dataclass, NamedTuple, attrs o pydantic
Ponte a prueba
Práctica que se adapta a ti
Practica esta lección
12 preguntas sobre 10 ideas de esta lección. Cada respuesta se explica al momento, y lo que aciertas se guarda en este navegador.
Validación, copias e igualdad: __post_init__, replace() y las trampas, reproducidas Pro: se abre con un pase Pro, Premium o Ultimate
Los objetos de datos reales necesitan reglas: un nombre no puede estar vacío, una edad tiene que ser posible, un total se calcula, no se escribe a mano. Esta parte valida y deriva campos en __post_init__, copia objetos sin compartir sus listas y reproduce las reglas de igualdad que sorprenden a la gente.
En esta parte:
- Validar y derivar campos al crear cada objeto
- Copias: replace() es superficial, asdict() es profunda
- Una igualdad que compara menos, o nada
2 diagramas · 3 ejemplos ejecutables (Python) · unos 8 minutos
Abriendo esta parte con tu pase…
Esta parte se abre con cualquier pase de MySmartCoPilot.
- Pase Pro · 1 semana79 ₹2,99 US$
- 30 días179 ₹5,99 US$
- 1 año1699 ₹45 US$
Un solo pago; un pase nunca se renueva. El precio que se muestra es el total que pagas: al pagar no se añaden comisiones ni cargos.
Ahora mismo no se pueden comprar pases, así que esta parte no se puede abrir de momento. La parte gratuita de arriba se sostiene por sí sola. Si tienes un pase, introduce tu clave de licencia.
También abre todas las demás partes en profundidad de Learn y todas las herramientas Pro. Las ventas son definitivas, salvo cuando la ley te da un derecho de desistimiento, por ejemplo en la UE y el Reino Unido (política de reembolso (en inglés)).
Objetos congelados, herencia y memoria a fondo, medidos, y un ejercicio Pro: se abre con un pase Pro, Premium o Ultimate
Las opciones interactúan: congelar cambia el hash y __post_init__, la herencia cambia el orden de los campos, y los slots cambian la memoria. Esta parte trabaja cada interacción, mide la memoria de cuatro tipos de registro y termina con una reserva de tren construida con dataclasses.
En esta parte:
- Reglas del hash, y campos derivados en una clase congelada
- Herencia y orden de los campos
- Memoria por registro, medida
- Ejercicio: una reserva de tren construida con dataclasses
- Una reserva de tren construida con dataclasses
- Resultados de las pruebas de ejemplo
3 ejemplos ejecutables (Python) · 1 ejercicio con pruebas de ejemplo · unos 8 minutos
Abriendo esta parte con tu pase…
Esta parte se abre con cualquier pase de MySmartCoPilot.
- Pase Pro · 1 semana79 ₹2,99 US$
- 30 días179 ₹5,99 US$
- 1 año1699 ₹45 US$
Un solo pago; un pase nunca se renueva. El precio que se muestra es el total que pagas: al pagar no se añaden comisiones ni cargos.
Ahora mismo no se pueden comprar pases, así que esta parte no se puede abrir de momento. La parte gratuita de arriba se sostiene por sí sola. Si tienes un pase, introduce tu clave de licencia.
También abre todas las demás partes en profundidad de Learn y todas las herramientas Pro. Las ventas son definitivas, salvo cuando la ley te da un derecho de desistimiento, por ejemplo en la UE y el Reino Unido (política de reembolso (en inglés)).
Preguntas de entrevista
-
De júnior a nivel medio · Calentamiento
¿Qué escribe el decorador @dataclass para una clase, y qué no hace?
Lee en orden los campos anotados de la clase y escribe un __init__ que los recibe como parámetros, con sus valores por defecto; un __repr__ que muestra cada campo por su nombre; y un __eq__ que compara campo a campo dos objetos de la misma clase. También escribe __match_args__ para la coincidencia de patrones. Las opciones añaden más: order=True escribe los cuatro métodos de orden, frozen=True rechaza la asignación y escribe __hash__, slots=True añade __slots__ y kw_only=True hace que los parámetros sean solo por nombre. No comprueba los tipos en tiempo de ejecución: las anotaciones son solo información para los lectores y los comprobadores de tipos, así que un tipo equivocado se acepta salvo que __post_init__ lo compruebe. Tampoco copia los valores por defecto mutables; un valor por defecto de lista tiene que venir de field(default_factory=list).
-
De júnior a nivel medio
¿Por qué @dataclass rechaza items: list = [] con un ValueError, mientras que una clase normal con def __init__(self, items=[]) se acepta? ¿Qué sale mal en la clase normal, y cómo lo arregla default_factory?
-
De nivel medio a sénior
Un servicio guarda en caché resultados de búsqueda en un dict cuya clave es una dataclass Query. Alguien quitó frozen=True para permitir pequeños arreglos en las consultas, y ahora las búsquedas fallan con "unhashable type". Un compañero sugiere unsafe_hash=True. Evalúa la sugerencia y propón un diseño mejor.
-
De sénior a staff
Una API HTTP recibe pedidos en JSON. ¿Los modelarías con dataclasses, con modelos de pydantic o con TypedDict? Compara la validación, la conversión, la velocidad y dónde va cada uno en el código, y di qué elegirías.
Para recordar
@dataclassescribe__init__,__repr__y__eq__a partir de los campos anotados de una clase.- Los valores por defecto mutables necesitan
field(default_factory=list); un[]sin más se rechaza. frozen=Truehace que los objetos sean inmutables y hashables;order=True,slots=Trueykw_only=Trueañaden comparaciones, slots y parámetros solo por nombre.- Las anotaciones no se comprueban en tiempo de ejecución: valida en
__post_init__, o usa pydantic para los datos de fuera.
Términos de esta lección
- dataclass
- Una clase decorada con @dataclass. El decorador escribe su __init__, su __repr__ y su __eq__ a partir de los campos anotados en su cuerpo, como name: str y quantity: int = 1, y opciones como frozen=True u order=True añaden más.
- campo de una dataclass
- Una línea con una anotación de tipo en el cuerpo de una dataclass, como quantity: int = 1. Su nombre pasa a ser un parámetro del __init__ escrito, con su valor por defecto si lo tiene; field() añade opciones como default_factory o compare=False.
- dataclass congelada
- Una dataclass declarada con frozen=True. Asignar a un campo después de crear el objeto lanza FrozenInstanceError, y con el eq=True por defecto el decorador también escribe un __hash__ a partir de los campos, así que los objetos pueden ser claves de un dict.
Referencias
- dataclasses: clases de datos (en inglés) (Python Software Foundation)
- dataclasses: valores por defecto mutables (en inglés) (Python Software Foundation)
- dataclasses: procesamiento después de init (en inglés) (Python Software Foundation)
- dataclasses: instancias congeladas (en inglés) (Python Software Foundation)
- copy.replace() (en inglés) (Python Software Foundation)
- typing.NamedTuple (en inglés) (Python Software Foundation)
- PEP 557: clases de datos (en inglés) (Python Software Foundation)
- Documentación de attrs (en inglés) (The attrs contributors)
- Documentación de Pydantic: modelos (en inglés) (Pydantic)
Herramientas relacionadas
Informar de un problema con esta lección (en inglés)
Solo se guarda en este navegador. Tu progreso en Learn (en inglés)