Chapter 9 · practice
Inheritance and Polymorphism
Different Objects, the Same Operation
Every question in this course has been the same kind of question: a prompt checked against one stored text answer. Real quizzes are not like that.
A text question compares what was typed.
A multiple-choice question accepts one of several options by letter.
A numeric question accepts anything close enough to the right number.
Three different rules for deciding correctness. The interesting part is what the rest of the program should have to know about them.
The numeric examples use one small built-in helper. abs(number) returns the number’s distance from zero, so abs(-0.05) is 0.05. Comparing that distance with a tolerance tells us whether a numeric response is close enough.
The version that knows everything
Here is the obvious first attempt, and the reason this chapter exists:
It works. Now think about what happens next.
A fourth kind arrives, say true or false. You add a branch here. Then scoring needs to know the kind, so it grows the same chain. Then display, then the report, then whatever reads questions from storage.
The kind return False and is wrong for everybody.
The signal
The pattern to recognize is a chain of
if kind == "text":
...
elif kind == "choice":
...
elif kind == "numeric":
...
One of these chains is fine. The problem is that they breed, and copies of the same chain in different
Compare it with a chain that is not this pattern:
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
This asks about a
Which chain is the warning sign this chapter addresses?
The move
The way out is the idea Chapter 4 introduced and this chapter finishes: put the behavior on the object.
There is one deliberate rough edge: NumericQuestion.is_correct("three") raises
The question.is_correct(response) three times, gets three different rules, and contains no
Each object knows what it is, so nothing else has to. Adding a fourth type means writing one class that honors the same operations; consumers such as this loop keep working unchanged.
Using several different
What this chapter is really about
You may have noticed those three classes were written without any of the machinery inheritance is usually introduced with. There is no base class, and nothing is shared.
That is deliberate. Polymorphism is the goal, and inheritance is one way to reach it, useful in narrower circumstances than most introductions suggest. The next two lessons show how far you can get with no inheritance at all, so that when it appears in Lesson 4 you can judge whether it is earning its place.
Task
This program decides everything by asking what kind of question it has, in two separate places that have already drifted: score_quiz handles three kinds, and describe_all handles only two.
The three validated question classes are supplied. Replace both
Then rewrite score_quiz(questions, responses) and describe_all(questions) so neither contains an
The point values stay as they are. Concentrate on the one new difficulty: consumer code that asks every object for the same operation without type tests.