0%

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

Try it

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:

Try it

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.

WertEntität
BeispielPoints, QuestionQuizAttempt
GleichheitInhalteIdentität
EingefrorenMeistensMeistens nicht
HashwertInhalte, wenn die Felder es erlaubenIdentitä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.