Il decoratore @dataclass è uno degli strumenti introdotti in Python 3.7 per ridurre il codice boilerplate nella creazione di semplici classi di contenimento dei dati. Grazie alle annotazioni di tipo, Python genera automaticamente i metodi __init__, __repr__, __eq__ e altri.
Storia della questione:
Prima dell'introduzione di dataclass, gli sviluppatori scrivevano manualmente classi boilerplate, implementando costruttori, metodi di confronto, repr, e spesso passavano a tuple nominate o librerie come attrs. L'introduzione di @dataclass ha standardizzato e semplificato questo processo.
Problema:
Il codice boilerplate, la duplicazione dei costruttori e dei metodi di confronto portavano spesso a errori e complicavano la manutenzione di grandi applicazioni.
Soluzione:
L'uso delle annotazioni di tipo e del decoratore speciale @dataclass consente di generare automaticamente tutti i metodi necessari nella classe.
Esempio di codice:
from dataclasses import dataclass @dataclass class Point: x: int y: int p1 = Point(10, 20) p2 = Point(10, 20) print(p1 == p2) # True, __eq__ generato automaticamente print(p1) # Point(x=10, y=20), __repr__ generato automaticamente
Caratteristiche principali:
Il @dataclass modifica il comportamento dell'ereditarietà (particolarità nell'ereditarietà)?
Sì. Nell'ereditarietà delle classi dataclass è necessaria particolare attenzione: i campi della classe base vengono prima dei campi della classe derivata, possono sorgere errori in caso di conflitto tra costruttori/ordine degli argomenti. Se la classe base e la derivata hanno campi con lo stesso nome, l'ultimo sovrascriverà il precedente.
Si possono usare valori mutabili per i campi predefiniti in dataclass?
No, non è possibile utilizzare direttamente oggetti come predefiniti (ad esempio, una lista) — bisogna usare field(default_factory=list). Altrimenti, tutte le istanze della classe condivideranno la stessa collezione.
Esempio:
from dataclasses import dataclass, field @dataclass class User: values: list = field(default_factory=list)
È @dataclass veloce per qualsiasi scenario? È adatto per l'ottimizzazione dell'archiviazione di grandi insiemi di dati?
No. dataclass non è la soluzione più efficiente per l'ottimizzazione della memoria. Per memorizzare milioni di oggetti è meglio usare __slots__, namedtuple o strutture speciali — dataclass aggiunge campi ausiliari e non risparmia memoria come i slots. È possibile combinarlo passando il parametro slots=True (Python 3.10+), oppure utilizzare manualmente gli slots.
@dataclass class Cart: items: list = [] # errore! c1 = Cart() c2 = Cart() c1.items.append("a") print(c2.items) # ['a'] — tutte le Cart condividono la stessa lista
Pro:
Contro:
from dataclasses import dataclass, field @dataclass class Cart: items: list = field(default_factory=list) c1 = Cart() c2 = Cart() c1.items.append("a") print(c2.items) # []
Pro:
Contro:
field(default_factory=...) (che richiede uno studio separato).