PythonStory_ClassRelationships.html
copyright © James Fawcett
Revised: 04/26/2026
6.0 Prologue
Classes rarely stand alone. This chapter examines how Python classes relate to each
other: single and multiple inheritance, the Method Resolution Order, mixin patterns,
abstract base classes for interface contracts, and composition as an alternative to
inheritance.
6.1 Single Inheritance
A class inherits all attributes and methods of its parent. Override a method by
redefining it; call the parent implementation via super():
class Animal:
def __init__(self, name: str) -> None:
self.name = name
def speak(self) -> str:
raise NotImplementedError
def __repr__(self) -> str:
return f"{type(self).__name__}({self.name!r})"
class Dog(Animal):
def speak(self) -> str:
return f"{self.name} says Woof!"
class GuideDog(Dog):
def __init__(self, name: str, owner: str) -> None:
super().__init__(name)
self.owner = owner
def speak(self) -> str:
return super().speak() + " (guide)"
6.2 Multiple Inheritance and MRO
Python supports multiple inheritance. The Method Resolution Order (MRO)
— computed by the C3 linearization algorithm — determines which class's
method is called when the same name appears in multiple bases:
class A:
def greet(self): return "A"
class B(A):
def greet(self): return "B->" + super().greet()
class C(A):
def greet(self): return "C->" + super().greet()
class D(B, C):
pass
print(D().greet()) # B->C->A
print(D.__mro__) # (D, B, C, A, object)
Inspect the MRO with ClassName.__mro__ or
ClassName.mro(). Always use super() (not hard-coded parent
names) to cooperate correctly with the MRO.
6.3 Mixins
A mixin is a class that provides methods for reuse without being a
meaningful base type on its own. Mixins are listed as additional bases and rely on the
MRO to combine cleanly:
class JsonMixin:
def to_json(self) -> str:
import json
return json.dumps(self.__dict__)
class LogMixin:
def log(self, msg: str) -> None:
print(f"[{type(self).__name__}] {msg}")
class User(JsonMixin, LogMixin):
def __init__(self, name: str, email: str) -> None:
self.name = name
self.email = email
u = User("Alice", "alice@example.com")
print(u.to_json())
u.log("created")
6.4 Abstract Base Classes
The abc module provides ABC and abstractmethod to
declare interface contracts that subclasses must fulfill. Instantiating a class with
unimplemented abstract methods raises TypeError:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
@abstractmethod
def perimeter(self) -> float: ...
def describe(self) -> str:
return f"area={self.area():.2f}, perim={self.perimeter():.2f}"
class Circle(Shape):
def __init__(self, radius: float) -> None:
self.radius = radius
def area(self) -> float:
import math
return math.pi * self.radius ** 2
def perimeter(self) -> float:
import math
return 2 * math.pi * self.radius
The collections.abc module also defines ABCs for standard protocols:
Iterable, Mapping, Sequence, Callable, etc.
6.5 Composition vs Inheritance
Inheritance models an is-a relationship; composition models a has-a
relationship. Composition is often more flexible because it avoids tight coupling and
deep hierarchies:
class Engine:
def start(self) -> str:
return "vroom"
class Car:
def __init__(self) -> None:
self._engine = Engine() # composition
def start(self) -> str:
return self._engine.start()
A useful heuristic: prefer composition when you want to reuse behavior; prefer
inheritance when you need polymorphism through a common base type.
6.6 isinstance and issubclass
isinstance(obj, T) returns True if obj is an
instance of T or any subclass.
issubclass(Sub, Base) checks the class hierarchy.
Both accept a tuple of types: isinstance(x, (int, float)).
In duck-typed code, prefer checking for the protocol (e.g., hasattr)
rather than the class, unless you specifically need to guard against an exact type.
6.7 Epilogue
This chapter covered Python's inheritance model, the MRO, mixins, abstract base classes,
and the composition alternative. The next chapter examines Python's generic type system
through the typing module.
6.8 References
abc module — python.org
collections.abc — python.org
super() — Real Python
Inheritance vs Composition — Real Python