When several classes share most of their behavior, put the general behavior in a parent class and derive more specific subclasses. An Employee can extend Person with an ID, department, and salary; Car, Truck, and Bicycle can extend Vehicle. The subclass keeps the parent’s interface while adding or modifying functionality, reducing duplicated code. section 9.15
Inheritance expresses an “is-a” relationship: an employee is a person, and a car is a vehicle. A Bowl containing Scoop objects expresses “has-a,” which is composition instead. Choosing between these relationships prevents every pair of related classes from becoming an inheritance hierarchy. section 9.7
Python resolves inherited behavior through a lookup process:
- Search the instance first, then its class, then the class’s parents, continuing to object if necessary. section 9.10
- Use a subclass method when specialized behavior should replace the parent method; otherwise, inherit the existing implementation unchanged. section 9.10
- Call super().__init__ when a subclass adds initialization but should retain the parent’s setup. section 9.15 section 9.27
- Reference self.max_scoops rather than Bowl.max_scoops when one inherited method must use different class-level values for different subclasses. section 9.17
A subclass reuses and extends a parent
class Foo(): def __init__(self, x): self.x = x def x2(self): return self.x * 2 class Bar(Foo): def x3(self): return self.x * 3 b = Bar(10) print(b.x2()) # inherited: 20 print(b.x3()) # subclass behavior: 30 Bar receives Foo’s initializer and x2 method without redefining them, then adds x3. The same pattern supports a BigBowl that changes only the scoop limit, or a FlexibleDict that changes only key retrieval. section 9.10 section 9.22 section 9.17
Inheritance is useful but should not be automatic. It can reduce code size and improve maintenance when subclasses genuinely specialize a parent. It can also produce oversized, difficult hierarchies. Extending built-in types is possible, but behavior should remain unambiguous; FlexibleDict is useful as practice while its guessing behavior is discouraged. section 9.20 section 9.22
class Foo():
def __init__(self, x):
self.x = x
def x2(self):
return self.x * 2
class Bar(Foo):
def x3(self):
return self.x * 3
b = Bar(10)
print(b.x2()) #1
print(b.x3()) #2
Runnable Foo and Bar code makes inherited initialization, reused methods, and subclass-specific behavior visible in a minimal example. section 9.10


















