Dataclass
- #python
- #programmazione
- #dataclass
- #class
In questa lezione
1. Introduzione
Le @dataclass in Python automatizzano la creazione di alcuni metodi speciali per le classi, che altrimenti dovremmo definire manualmente.
Questo include metodi come __init__, __repr__, __eq__, semplificando notevolmente la gestione di classi che fungono principalmente da contenitori di dati.
Per utilizzarle, basta importare il decoratore @dataclass dal modulo dataclasses:
from dataclasses import dataclass
e applicarlo alla classe:
@dataclass
class NomeClasse:
...
2. Esempio pratico
Vediamo la differenza tra una classe normale e una @dataclass con un esempio concreto.
-
Senza usare la
@dataclass:class Point: x: int y: int def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return f"Point(x={self.x}, y={self.y})" def __eq__(self, other): return self.x == other.x and self.y == other.y p1 = Point(1, 2) p2 = Point(2, 1) print(p1, p2) print(p1 == p2)Output: Point(x=1, y=2) Point(x=2, y=1) FalseCome si può vedere, dobbiamo scrivere manualmente sia il costruttore (
__init__), sia i metodi__repr__e__eq__. -
Usando la
@dataclass:from dataclasses import dataclass @dataclass class Point: x: int y: int p1 = Point(1, 2) p2 = Point(2, 1) print(p1, p2) print(p1 == p2)Output: Point(x=1, y=2) Point(x=2, y=1) FalseL’output è lo stesso, ma non è stato necessario definire a mano i metodi
__init__,__repr__o__eq__. La@dataclassli ha generati automaticamente.
3. Dettagli automatici
Quando usiamo @dataclass, Python genera automaticamente i seguenti metodi:
__init__: per inizializzare gli attributi__repr__: per rappresentare l’oggetto in modo leggibile__eq__: per confrontare due oggetti
4. Esempio Avanzato
Ecco un altro esempio, in cui definiamo una classe per un inventario:
from typing import ClassVar
from dataclasses import dataclass
@dataclass
class InventoryItem:
"""Classe per tenere traccia di un articolo di inventario"""
name: str
unit_price: float
quantity_on_hand: int = 0
class_var: ClassVar[int] = 100
Nota
Quando vogliamo indicare che un attributo appartiene alla classe (e non all’istanza), possiamo usare ClassVar.
Queste variabili non vengono incluse nel costruttore generato automaticamente.
5. Ignorare o escludere variabili dal costruttore
In alcuni casi, potremmo voler escludere certi attributi dal costruttore automatico o dall’output del __repr__.
Possiamo ottenere questo comportamento con field() dal modulo dataclasses.
from dataclasses import dataclass, field
@dataclass
class Libro:
titolo: str
autore: str
prezzo: float
_iva: float = field(default=0.1, repr=False)
Nota
field() consente di controllare come gli attributi vengono trattati dalla dataclass:
init=False: esclude l’attributo dal costruttorerepr=False: lo nasconde nella rappresentazione testualecompare=False: lo esclude dal confronto==
6. Ereditarietà
6.1 Classi miste
Quando ereditiamo da una classe che non è una @dataclass, è necessario gestire manualmente alcune parti dell’inizializzazione.
from dataclasses import dataclass
class Rectangle:
def __init__(self, height, width):
self.height = height
self.width = width
@dataclass
class Square(Rectangle):
side: float
def post_init(self):
super().init(self.side, self.side)
Nota
Il metodo __post_init__ viene eseguito automaticamente dopo il costruttore generato da @dataclass.
È utile quando servono operazioni di inizializzazione aggiuntive.
Esempio:
from dataclasses import dataclass
@dataclass
class Prodotto:
nome: str
prezzo: float
iva: float = 0.22
def __post_init__(self):
self.prezzo_lordo = self.prezzo * (1 + self.iva) 6.2 Ereditarietà con sole dataclass
Quando sia la classe base che quella derivata sono @dataclass, Python gestisce tutto automaticamente.
Vediamo un esempio:
from dataclasses import dataclass
@dataclass
class Rectangle:
width: int
length: int
@dataclass
class ColorRectangle(Rectangle):
color: str
rect = ColorRectangle(10, 10, "green")
In questo caso, non è necessario definire manualmente né il costruttore né il metodo __post_init__,
poiché tutto viene generato automaticamente da Python.
7. Opzioni aggiuntive di decorazione
| Opzione | Significato |
|---|---|
frozen=True | Rende gli oggetti immutabili |
order=True | Genera anche i metodi di confronto <, <=, > e >= |
kw_only=True (da Python 3.10) | Rende obbligatorio passare i parametri per nome |
Esempio:
from dataclasses import dataclass
@dataclass(frozen=True, order=True)
class Punto:
x: int
y: int
8. Esercizi
8.1 Esercizio
Creare una @dataclass chiamata “Libro” con:
- titolo (stringa)
- autore (stringa)
- prezzo (float)
- metodo
__post_init__che calcolaprezzo_ivatocon IVA al 10% - proprietà
descrizioneche restituisce una stringa tipo"Titolo di Autore - Prezzo: XX€"
9. Quiz a risposta multipla
Mettiti alla prova
0/10 risposte
1) Qual è lo scopo principale del decoratore @dataclass in Python?
2) Quale modulo è necessario importare per usare le dataclass?
3) Quale dei seguenti metodi viene generato automaticamente da @dataclass?
4) Cosa fa il parametro repr=False nel campo definito con field()?
5) Come si esclude un attributo dal costruttore automatico di una dataclass?
6) Qual è lo scopo del metodo __post_init__ in una dataclass?
7) Quale opzione del decoratore dataclass rende un oggetto immutabile?
8) Quando è utile usare ClassVar all'interno di una dataclass?
9) Quale parametro del decoratore dataclass genera anche i metodi di ordinamento (<, <=, >, >=)?
10) Quale vantaggio offre l'uso di @dataclass rispetto a una classe tradizionale?