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 call super().__init__()?
  • Why does describe() in a base class run the subclass's speak()?
  • What does isinstance(x, Iterable) check, and why exclude str from a sequence test?
  • Which two methods make a class a full collections.abc.Sequence?
  • For class D(B, C) where both inherit from A, what is D.__mro__, and what does super() in B call?
  • What does @runtime_checkable change about a Protocol?
  • Why does dict.update bypass 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 1

Plugin 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: 25

Lower-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
6

In this module: Inheritance, protocols and duck typing

← Composition over inheritance — Liskov, delegation and wrapping built-ins · Exceptions — try, except, else, finally, raise →