Lektionen des Moduls (2/4)
dataclasses: Datenklassen ohne Boilerplate
Der Dekorator @dataclass (Modul dataclasses) generiert automatisch __init__, __repr__ und __eq__ für Klassen, deren einzige Aufgabe es ist, Daten zu speichern. Weniger Boilerplate, klarerer Code.
Ohne Dataclass (Boilerplate)
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)Mit Dataclass
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, 4Das Muster: Deklariere Felder als Klassenannotationen (name: type), optional mit einem Standardwert. @dataclass generiert den Rest.
Standardwerte und default_factory
from dataclasses import dataclass, field
@dataclass
class Articolo:
nome: str
prezzo: float = 0.0
tag: list[str] = field(default_factory=list)frozen=True: unveränderlich
@dataclass(frozen=True)
class Coordinata:
lat: float
lon: float
c = Coordinata(45.4, 9.2)
c.lat = 99 # FrozenInstanceError!Mit frozen deklarierte Dataclasses sind auch hashbar (hashable): Du kannst sie als Dictionary-Schlüssel oder Set-Elemente verwenden.
order=True: automatische Vergleiche
@dataclass(order=True)
class Voto:
valore: int
Voto(10) < Voto(20) # True
sorted([Voto(30), Voto(10), Voto(20)])Generiert __lt__, __le__, __gt__, __ge__, indem die Felder in der Reihenfolge ihrer Deklaration verglichen werden.
Normale Methoden
Dataclasses bleiben normale Klassen: Du kannst Methoden hinzufügen.
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.0Unveränderliche und effiziente Dataclasses
Du kannst eine Dataclass unveränderlich machen, indem du dem Dekorator das Argument frozen=True übergibst: @dataclass(frozen=True). Dies führt zu einem Fehler bei jedem Versuch, Attribute nach der Instanziierung zu verändern, wodurch Instanzen für nebenläufige Umgebungen oder als Dictionary-Schlüssel geeignet sind.
Probiere es aus
Erstelle eine Dataclass `Book` mit den Feldern `title: str` und `pages: int`. Instanziiere sie als `l = Book('Moby Dick', 635)`. Evaluiere `l == Book('Moby Dick', 635)`.
Hinweis anzeigen
@dataclass generiert __eq__, indem Feld für Feld verglichen wird.
Lösung nach 3 Versuchen verfügbar
Wiederholungsübung
Erstelle eine Dataclass `Basket` mit dem Feld `items: list[str]` und default_factory=list. Instanziiere `c1 = Basket()` und `c2 = Basket()`, hänge 'mela' an c1.items an. Evaluiere `(c1.items, c2.items)`, um zu überprüfen, dass es sich NICHT um dieselbe Liste handelt.
Hinweis anzeigen
field(default_factory=list) garantiert eine neue Liste pro Instanz.
Lösung nach 3 Versuchen verfügbar
Zusätzliche Herausforderung
Importiere `dataclass` aus `dataclasses`. Erstelle eine Dataclass `Point` mit zwei float-Koordinaten `x` und `y`. Instanziiere einen Punkt mit `x=1.5` und `y=2.5` und speichere ihn in `p`. Evaluiere schließlich `p`.
Hinweis anzeigen
Verwende @dataclass über der Klasse Point und deklariere x: float und y: float.
Lösung nach 3 Versuchen verfügbar