Vererbung und Polymorphie · Abschlussprojekt
Abschlussprojekt: Projekt: Mehrere Fragearten unterstützen
Der Kurs begann mit einem Quiz aus gleich aufgebauten Dictionary-Fragen und einer Prüffunktion, die die Regel kannte. Am Ende dieses Kapitels hält ein Quiz vier Fragearten und wird von Code bewertet, der keine davon kennt.
Was du baust
Question the base: prompt, points, optional collaborators
TextQuestion matches ignoring spaces and case
ChoiceQuestion matches one option
NumericQuestion matches within a tolerance
SurveyQuestion ungraded, always correct
TimeLimit a thing a question has
Hint a thing a question has
Quiz holds questions of any kind
ScoreReport turns an attempt into lines
Vier Unterklassen, weil jede eine tatsächlich andere Art ist, eine Ebene tief. Zwei Partnerklassen, weil sich Zeitbegrenzung und Hinweise mit allen vier frei kombinieren lassen.
Die Zusage jeder Unterklasse
is_correct(response) nimmt einen beliebigen String entgegen und gibt True oder False zurück. Es löst niemals eine Ausnahme aus und gibt niemals etwas anderes zurück.
Wegen dieses Satzes lassen sich Quiz und ScoreReport einmal schreiben. Die Bewertung prüft ihn für jede Unterklasse mit einer leeren und einer unsinnigen Antwort. Das ist die einfache Version des Familientests, den Kapitel 13 ausführlich aufbaut.
SurveyQuestion wird nicht bewertet und ist immer richtig. Warum ist es eine Unterklasse statt einer eigenen, nicht verwandten Klasse?
Regeln, die die Bewertung prüft
Keine Funktion außerhalb der Klassen verwendet
isinstanceoder nennt eine Unterklasse.Jede Unterklasse gibt aus
is_correctfür einen beliebigen String einen booleschen Wert zurück.describe()wird einmal geschrieben, in der Basis.Keine Klasse verwendet eine Ausgabe.
Eine fünfte Frageart, die die Bewertung erfindet, funktioniert überall ohne Änderung.
Der letzte Punkt ist der eigentliche Test dieses Kapitels. Wird eine später geschriebene Klasse von jemandem, der deinen Code nie gesehen hat, korrekt bewertet und dargestellt, erfüllt der Entwurf seine Zusage.
Fertigstellen
Lies dein fertiges Quiz und ScoreReport und zähle, wie oft sie eine bestimmte Frageart erwähnen. Die Antwort sollte null sein.
Erfinde dann eine fünfte Art. Eine Wahr-oder-falsch-Frage, eine Schlüsselwortfrage mit mehreren akzeptierten Schreibweisen oder eine Bereichsfrage eignen sich. Füge sie zum Quiz hinzu, ohne Quiz oder ScoreReport zu bearbeiten. Wenn dieses neue Verhalten durch das unveränderte Programm läuft, hast du das Projektziel erreicht.
Aufgabe
Die validierten Partnerklassen und die Basisklasse sind vorgegeben. Baue die konkrete Familie und die beiden Klassen, die sie ohne Kenntnis konkreter Typen verwenden.
Question(prompt, points, timing=None, hint=None) hält den gemeinsamen Zustand. describe() gibt "<prompt> (<points> points)" zurück, gefolgt von der Beschreibung jedes vorhandenen Partners, Zeitbegrenzung vor Hinweis. is_correct(response) löst NotImplementedError aus. Ergänze eine Property kind_label, die "question" zurückgibt.
Die vier Unterklassen überschreiben jeweils is_correct und kind_label. Keine definiert describe neu:
TextQuestion(prompt, points, answer, ...), Bezeichnung"text", vergleicht ohne Leerraum an den Rändern und ohne Beachtung der Groß- und Kleinschreibung.ChoiceQuestion(prompt, points, correct_option, ...), Bezeichnung"multiple choice", akzeptiert die Option in beiden Schreibweisen.NumericQuestion(prompt, points, answer, tolerance, ...), Bezeichnung"numeric", vergleicht innerhalb der Toleranz und gibtFalsezurück, statt eine Ausnahme auszulösen, wenn die Antwort keine Zahl ist.SurveyQuestion(prompt, ...), Bezeichnung"survey", ist0Punkte wert und immer richtig.
TimeLimit(seconds) und Hint(text) sind vorgegeben und validiert. Behalte auch die bisherigen Konstruktionsregeln: Erwartete Textantworten und Auswahloptionen dürfen nicht leer oder nur Leerraum sein, die numerische Toleranz darf nicht negativ sein, und ein Quiztitel darf nicht leer sein. Lehne diese ungültigen Werte mit ValueError ab.
Quiz(title) hält Fragen, gibt sie sicher heraus und meldet question_count und total_points. ScoreReport(quiz, responses) gibt mit lines() pro Frage eine Zeile "<description>: correct" oder ": incorrect" zurück, dann "Score: <earned> of <total>" und dann "Kinds: <labels, comma separated, in order, without repeats>".
Quiz.add(None) löst ValueError aus. Ein Bericht muss genau eine Antwort pro Quizfrage erhalten. lines() löst sowohl bei zu wenigen als auch bei zu vielen ValueError aus, damit zip keine Daten unbemerkt verwirft.
Jedes is_correct muss für einen beliebigen String True oder False zurückgeben und darf niemals eine Ausnahme auslösen. Keine Klasse verwendet eine Ausgabe, und nichts außerhalb der Familie nennt eine Unterklasse.