0%

Objekte darstellen und vergleichen · Abschlussprojekt

Abschlussprojekt: Projekt: Quizobjekte verständlich und vergleichbar machen

Dieses Kapitel hat dir fünf Methoden gezeigt und, noch nützlicher, Regeln dafür, wann welche passt. Das Projekt ist vor allem eine Übung in Zurückhaltung: Drei der vier Klassen sollten am Ende weniger Methoden haben, als du ihnen vielleicht geben möchtest.

Die Entscheidungen

KlasseWas sie istErhält
PointsEin schreibgeschützter Wert mit natürlicher Ordnung__repr__, __eq__, __hash__, __lt__
QuestionEin schreibgeschützter Wert ohne natürliche Ordnung__repr__, __str__, __eq__, __hash__
ResponseEin Wert, den nur Entwickler sehen__repr__, __eq__
QuizAttemptEin Ereignis mit eigener Identität__repr__, __str__

Zwei dieser Fälle verdienen einen genaueren Blick.

Points und Question halten jedes Attribut, das ihr Hashwert verwendet, schreibgeschützt. Könnte sich einer dieser Werte nach dem Einfügen in ein Set ändern, würde das Wiederfinden möglicherweise scheitern, obwohl das Objekt noch enthalten ist.

Response erhält __eq__, aber kein __hash__. Seine Frage und sein eingegebener Text ändern sich nicht. Eine Antwort wird jedoch niemals als Dictionary-Schlüssel oder Set-Element verwendet. Ein unnötiges __hash__ wäre das Versprechen, es für immer korrekt zu halten, ohne dafür einen Nutzen zu erhalten.

QuizAttempt definiert weder __eq__ noch __hash__ und behält damit Pythons standardmäßige Identitätsgleichheit und den identitätsbasierten Hashwert. Zwei Versuche derselben Person mit demselben Punktestand sind getrennte Ereignisse. Ihre Antworten dürfen sich ändern, ohne dass sich diese Identität oder der Hashwert ändert. Ein Hashwert auf Grundlage dieser veränderbaren Inhalte wäre unsicher.

Warum wäre ein inhaltsbasiertes __eq__ für QuizAttempt hier ein Fehler?

Was das Programm tut

Das aufrufende Programm baut einen kleinen Fragenbestand mit einem Duplikat auf, entfernt das Duplikat mit einem Set, sortiert den Rest nach Punkten, führt einen Versuch durch und gibt einen Bericht aus. Jeder Schritt nutzt etwas aus diesem Kapitel. Mit dem Standardverhalten einer neuen Python-Klasse funktioniert diese Verarbeitung noch nicht.

Fertigstellen

Lies deine fertigen Klassen und prüfe jede Methode mit einer Frage: Was würde nicht mehr funktionieren, wenn sie gelöscht würde? Falls nichts, lösche sie. Ein __hash__ in einer Klasse, die nie als Schlüssel dient, ein __str__, das nur die repr-Darstellung wiederholt, und ein __lt__ für etwas ohne offensichtliche Ordnung sind wartungsbedürftiger Code ohne Gegenwert.

Ergänze zum Schluss ein eigenes Duplikat und eine eigene neue Frage im Bestand. In der Ausgabe sollte das Duplikat verschwinden und die neue Frage nach Punkten eingeordnet bleiben. Alles soll lesbar bleiben, ohne eine der beiden erwarteten Antworten zu verraten.

Aufgabe

Ergänze die speziellen Methoden aus der Tabelle der Lektion. Die vorgegebenen öffentlichen Vorgänge müssen weiter funktionieren; kleine Hilfsmethoden sind willkommen.

Points: schreibgeschützter Betrag; repr-Darstellung Points(3); Gleichheit, Hashing und Ordnung anhand des Betrags.

Question: schreibgeschützter Fragetext, erwartete Antwort und Punkte; repr-Darstellung Question('...', '...', Points(2)); str-Darstellung <prompt> (2 points), die die erwartete Antwort nicht verraten darf; Gleichheit und Hashing anhand von Fragetext, erwarteter Antwort und Punkten.

Response: schreibgeschützte Frage und eingegebener Text sowie festgehaltene Momentaufnahmen von Richtigkeit, verfügbaren Punkten und verdienten Punkten; repr-Darstellung Response(given='3', earned=2); Gleichheit anhand von Frage und eingegebenem Text. Kein __hash__.

QuizAttempt: Zusammenfassung QuizAttempt(learner='Mina', response_count=2) als repr-Darstellung; str-Darstellung Mina: 4 points. Keine Überschreibung von __eq__ oder __hash__: Behalte das geerbte Identitätsverhalten.

Schreibe anschließend unique_sorted(questions), das die unterschiedlichen Fragen in aufsteigender Reihenfolge ihrer Punkte zurückgibt. Verwende ein Set zum Entfernen von Duplikaten und eine Schlüsselfunktion zum Sortieren. Keine dieser Entscheidungen gehört in Question.

Jedes __eq__ muss bei einem anderen Typ NotImplemented zurückgeben.