Python Inheritance Quiz: MRO, ABCs, Protocols and Duck Typing
Test your Python OOP with 12 questions and three programs on super, duck typing, abstract base classes, the MRO and mixins, Protocol and composition.
- Course: Python study plan
- Module: Inheritance, protocols and duck typing
- Kind: Checkpoint — cleared at 70%
- Reading time: 25 min
- Runtime: CPython 3.11
Checkpoint — Inheritance, protocols and duck typing is the checkpoint that closes the Inheritance, protocols and duck typing module: a graded quiz and whole-program exercises, passed at 70%.
Instructions
This checkpoint covers the whole module: subclassing with super() and attribute lookup, duck typing with EAFP and hasattr, abstract base classes and collections.abc, multiple inheritance with the MRO, cooperative super() and mixins, typing.Protocol with runtime_checkable, and composition over inheritance with Liskov, delegation and UserDict.
How it works. Twelve questions and three programs. You need 70% on the questions and every program accepted to clear the module. You can retake it as often as you like; your best score counts.
Before you start, make sure you can answer these from memory:
- What happens when a subclass defines
__init__and does not callsuper().__init__()? - Why does
describe()in a base class run the subclass'sspeak()? - What does
isinstance(x, Iterable)check, and why excludestrfrom a sequence test? - Which two methods make a class a full
collections.abc.Sequence? - For
class D(B, C)where both inherit fromA, what isD.__mro__, and what doessuper()inBcall? - What does
@runtime_checkablechange about aProtocol? - Why does
dict.updatebypass an overridden__setitem__, and what class fixes it?
The three programs are a shape hierarchy on an ABC with a template method, a plugin registry that validates objects against a runtime-checkable protocol, and a case-folding mapping built on UserDict alongside a stack that composes a list.
Common questions
Why does describe() in a base class run the subclass's speak()?
Because self is the subclass instance, and attribute lookup for self.speak starts at the instance's own class. Every Python method is effectively virtual, so the override runs with nothing declared.
For class D(B, C) where both inherit from A, what does super() in B call?
C's method. D.__mro__ is (D, B, C, A, object), and super() calls the next class in the MRO of the instance's type, so from B the next class is its sibling C, not its parent A.
Which two methods make a class a full collections.abc.Sequence?
__getitem__ and __len__. Inherit from Sequence and implement those two — handling a slice in __getitem__ if you want slicing — and it supplies __contains__, __iter__, __reversed__, index and count.
Exercises
Shape catalogue
Define Shape(ABC) with abstract area(), a concrete describe() returning <ClassName> <area with two decimals>, and __lt__ comparing areas so shapes sort. Implement Rect(w, h), Circle(r) and Square(Rect) (constructed with one side, passing it twice to super().__init__). Read shapes; print them sorted by area ascending (ties keep input order), then total <sum of areas> with two decimals, then squares <count> using isinstance against Rect and Square: rects <n> squares <m> where a square counts as both.
Input: lines rect w h, circle r, square s. Output: the sorted descriptions, then total …, then rects … squares ….
rect 2 3
square 2
circle 1
prints
Circle 3.14
Square 4.00
Rect 6.00
total 13.14
rects 2 squares 1Plugin registry
A @runtime_checkable protocol Plugin requires a data member name and a method run(x). Candidate classes are given: Doubler and Squarer conform, Broken lacks run, Anonymous lacks name. Read a line of class names to register — accept a candidate only if its instance satisfies the protocol, printing registered <name attr> or rejected <ClassName> — then read an integer and print <name>: <result> for every registered plugin in registration order.
Input: a line of class names, then an integer. Output: one line per candidate, then one line per registered plugin.
Doubler Broken Squarer Anonymous
5
prints
registered double
rejected Broken
registered square
rejected Anonymous
double: 10
square: 25Lower-casing mapping and a composed history
Build LowerDict(UserDict) whose keys are always stored lower-cased, and History, a class that composes a list to record every command as <n>: <command line> with add(line), last(k) returning the last k entries (fewer if there are fewer) and __len__. Commands: set K v, get K (missing when absent), del K (missing when absent), history k (prints the last k entries, one per line) and count (prints the number of recorded commands). Every command, including history and count, is recorded before it is executed.
Input: commands. Output: one line per get, per failed del, per count, and k lines per history.
set Name ada
get NAME
del name
del name
history 2
count
prints
ada
missing
4: del name
5: history 2
6In this module: Inheritance, protocols and duck typing
- Inheritance basics — subclasses, super() and attribute lookup
- Polymorphism and duck typing — EAFP, hasattr and programming to behaviour
- Abstract base classes — abc and collections.abc
- Multiple inheritance and the MRO — mixins and cooperative super()
- Protocols and structural typing — typing.Protocol
- Composition over inheritance — Liskov, delegation and wrapping built-ins
- Checkpoint — Inheritance, protocols and duck typing (this lesson)
← Composition over inheritance — Liskov, delegation and wrapping built-ins · Exceptions — try, except, else, finally, raise →