Vai al contenuto
eLearner.app
Modulo 9 · Lezione 2 di 434/36 nel corso~12 min
Lezioni del modulo (2/4)

dataclass: classi-dati senza boilerplate

Il decoratore @dataclass (modulo dataclasses) genera automaticamente __init__, __repr__ e __eq__ per classi che servono solo a contenere dati. Meno boilerplate, codice più chiaro.

Senza dataclass (boilerplate)

Python
class Punto:
    def __init__(self, x: float, y: float) -> None:
        self.x = x
        self.y = y
    def __repr__(self) -> str:
        return f"Punto(x={self.x}, y={self.y})"
    def __eq__(self, other) -> bool:
        if not isinstance(other, Punto):
            return NotImplemented
        return (self.x, self.y) == (other.x, other.y)

Con dataclass

Python
from dataclasses import dataclass

@dataclass
class Punto:
    x: float
    y: float

p = Punto(3, 4)
p             # Punto(x=3, y=4)   ← __repr__ gratis
Punto(3, 4) == Punto(3, 4)        # True ← __eq__ gratis
p.x, p.y      # 3, 4

Il pattern: dichiari i campi come annotazioni di classe (nome: tipo), opzionalmente con valore di default. @dataclass genera il resto.

Default e default_factory

Python
from dataclasses import dataclass, field

@dataclass
class Articolo:
    nome: str
    prezzo: float = 0.0
    tag: list[str] = field(default_factory=list)

frozen=True: immutabili

Python
@dataclass(frozen=True)
class Coordinata:
    lat: float
    lon: float

c = Coordinata(45.4, 9.2)
c.lat = 99   # FrozenInstanceError!

I dataclass frozen sono anche hashable: puoi usarli come chiavi di dict o elementi di set.

order=True: confronti automatici

Python
@dataclass(order=True)
class Voto:
    valore: int

Voto(10) < Voto(20)   # True
sorted([Voto(30), Voto(10), Voto(20)])

Genera __lt__, __le__, __gt__, __ge__ confrontando i campi nell'ordine di dichiarazione.

Metodi normali

I dataclass restano classi a tutti gli effetti: puoi aggiungere metodi.

Python
import math
from dataclasses import dataclass

@dataclass
class Punto:
    x: float
    y: float
    def distanza_dall_origine(self) -> float:
        return math.hypot(self.x, self.y)

Punto(3, 4).distanza_dall_origine()   # 5.0

dataclass immutabili ed efficienti

Puoi rendere una dataclass immutabile passando l'argomento frozen=True al decoratore: @dataclass(frozen=True). In questo modo, i tentativi di modificare un attributo dopo la creazione solleveranno un errore, rendendo gli oggetti sicuri per contesti concorrenti o per essere usati come chiavi nei dizionari.

Prova tu

Esercizio#python.m9.l2.e1
Tentativi: 0Caricamento…

Crea un dataclass `Book` con campi `title: str` e `pages: int`. Istanzialo come `l = Book('Moby Dick', 635)`. Valuta `l == Book('Moby Dick', 635)`.

Caricamento editor…
Mostra suggerimento

@dataclass genera __eq__ comparando campo per campo.

Soluzione disponibile dopo 3 tentativi

Esercizio di ripasso

Esercizio#python.m9.l2.e2
Tentativi: 0Caricamento…

Crea un dataclass `Basket` con campo `items: list[str]` con default_factory=list. Istanzia `c1 = Basket()` e `c2 = Basket()`, aggiungi 'mela' a c1.items. Valuta `(c1.items, c2.items)` per verificare che NON siano la stessa lista.

Caricamento editor…
Mostra suggerimento

field(default_factory=list) garantisce una lista nuova per istanza.

Soluzione disponibile dopo 3 tentativi

Sfida aggiuntiva

Esercizio#python.m9.l2.e3
Tentativi: 0Caricamento…

Importa `dataclass` da `dataclasses`. Crea una dataclass `Point` che contenga due coordinate float `x` e `y`. Istanzia un punto con `x=1.5` e `y=2.5` salvandolo in `p`. Valuta infine `p`.

Caricamento editor…
Mostra suggerimento

Usa @dataclass sopra la classe Point, e dichiara x: float e y: float.

Soluzione disponibile dopo 3 tentativi