0%

Vererbung und Polymorphie · Übung

Polymorphe Sammlungen verwenden

Ein Quiz enthält mehrere Fragearten gleichzeitig. In Kapitel 6 hatte jedes Question zufällig dasselbe Verhalten. Python-Listen selbst haben das nie verlangt. Jetzt ist der gemeinsame Vorgang wichtiger als die konkrete Klasse:

Try it

Quiz ist gegenüber Kapitel 6 unverändert. Es erwähnt weder TextQuestion noch ChoiceQuestion und muss das auch nicht: Es hält Fragen, und jede Frage kann sich beschreiben und ihre Punkte melden.

Eine Sammlung mit Elementen verschiedener Klassen, die über dieselben gemeinsamen Vorgänge verwendet werden, heißt polymorphe Sammlung. Hier zeigt sich ein großer Teil des Nutzens der letzten vier Lektionen.

Ein is_correct-Aufruf kann zu verschiedenen Question-Unterklassen mit ihrem eigenen Verhalten führen.

Ein gemischtes Quiz bewerten

Try it

Neun Zeilen, die sonst eine wachsende Kette von Typprüfungen wären. Eine zusätzliche Zahlenfrage ändert weder hier noch in Quiz noch im Bericht etwas.

Was muss sich in Quiz und score ändern, um eine vierte Frageart zu unterstützen?

Eine gemischte Sammlung sortieren und filtern

Die Werkzeuge aus Kapitel 7 funktionieren hier unverändert. Es lohnt sich, sie mit einer gemischten Liste zu sehen, denn dort zeigen sie ihren Nutzen:

Try it

Beide lesen points, das jede Frage hat. Keines weiß oder muss wissen, dass verschiedene Klassen enthalten sind.

Die Versuchung nachzusehen

Irgendwann scheint etwas tatsächlich den Typ zu benötigen. Ein Bericht möchte vielleicht zählen, wie viele Auswahlfragen ein Quiz enthält:

choice_count = 0
for question in quiz.questions():
    if isinstance(question, ChoiceQuestion):
        choice_count = choice_count + 1

Das funktioniert und ist die Typkette aus Lektion 1 in neuem Gewand. Die Klassenliste ist in den Bericht gewandert. Eine nicht verwandte Klasse mit demselben Auswahlverhalten würde übersehen. Unterklassen von ChoiceQuestion würden diese Prüfung weiterhin bestehen.

Meist ist der passende Ausweg, das Objekt etwas zu fragen:

Try it

Das Wissen darüber, was jede Klasse ist, bleibt bei der Klasse. Eine neue Art von Auswahlfrage hinzuzufügen hängt davon ab, was sie über sich meldet, nicht davon, jedes isinstance im Programm zu finden.

Das ist keine absolute Regel. isinstance ist an einer echten Grenze sinnvoll, etwa bei der Validierung von etwas, das von außerhalb deines Programms kam. Innerhalb einer selbst entworfenen Familie bedeutet es meist, dass der Basis ein Vorgang fehlt.

Die Übung baut ein Quiz mit vier Fragearten und einen Bericht darüber, ganz ohne Typprüfungen.

Aufgabe

Die validierte Familie mit vier Fragearten und die sichere Sammlung Quiz sind vorgegeben. Baue Sammlungsvorgänge, die nie nach der erhaltenen konkreten Art fragen.

Vervollständige drei Funktionen:

  • graded_questions(quiz) gibt die Fragen zurück, die mehr als null Punkte wert sind.

  • count_of_kind(quiz, label) gibt zurück, wie viele Fragen diese Bezeichnung melden.

  • report_lines(quiz, responses) gibt pro Frage eine Zeile "<description>: correct" oder "<description>: incorrect" zurück, anschließend "Score: <points> of <total>".

Keine der drei Funktionen darf isinstance verwenden oder eine Unterklasse nennen. Die Bewertung ergänzt eine selbst erfundene fünfte Frageart und erwartet, dass alle drei damit umgehen.