Dataclasses und Wertobjekte · Übung
Wertobjekte einfrieren
Kapitel 7 machte die Eingaben für Hashwerte mit Properties schreibgeschützt. Eine Dataclass kann dieselbe Entscheidung direkt ausdrücken.
Einen Wert einfrieren
Die Zuweisung wird abgelehnt:
points.amount = 5
Das Attribut amount lässt sich nicht neu zuweisen. Es enthält eine unveränderliche Ganzzahl. Damit bleibt der bei Gleichheit verwendete Wert stabil, und der erzeugte Hashwert ist sicher:
Warum ist der erzeugte Hashwert dieser eingefrorenen Klasse Points sicher?
Entitäten machen eine andere Zusage
Ein Versuch existiert, um sich zu verändern. Halte ihn veränderbar. Er repräsentiert außerdem ein Ereignis, daher müssen zwei inhaltlich übereinstimmende Versuche ihre Identitätsgleichheit behalten:
@dataclass(eq=False)
class QuizAttempt:
learner: str
responses: list = field(default_factory=list)
eq=False schaltet die erzeugte Wertgleichheit aus. Die gewöhnliche Identitätsgleichheit und das Hashing nach Identität bleiben erhalten.
| Wert | Entität | |
|---|---|---|
| Beispiel | Points, Question | QuizAttempt |
| Gleichheit | Inhalte | Identität |
| Eingefroren | Meistens | Meistens nicht |
| Hashwert | Inhalte, wenn die Felder es erlauben | Identität |
Einfrieren wirkt nur auf der obersten Ebene: Es verhindert die Zuweisung eines Attributs, aber eine darin gespeicherte veränderbare Liste kann sich weiterhin ändern. Ein tatsächlich unveränderlicher Wert sollte selbst unveränderliche Werte enthalten.
Die Übung ordnet drei Werte und eine Entität ein. Wie du neue Versionen eingefrorener Werte erzeugst, ist das einzelne Thema der nächsten Lektion.
Aufgabe
Friere ein, was eingefroren sein sollte, und bewahre die Identität von Entitäten.
Mache Points, Duration und Question zu eingefrorenen Dataclasses. Sie sollen Zuweisungen ablehnen und in Sets oder als Dictionary-Schlüssel funktionieren.
Behalte ihre Konstruktionsregeln in __post_init__: Punkte sind positiv; die Minuten einer Dauer sind nicht negativ und ihre Sekunden reichen von 0 bis einschließlich 59; eine Frage hat einen nicht leeren Fragetext, eine nicht leere erwartete Antwort und positive Punkte.
Lass QuizAttempt veränderbar und verwende eq=False, damit verschiedene Versuche nach Identität verglichen werden. Seine Liste responses muss für jeden Versuch eigenständig bleiben.