Inheritance lets a class specialize the behavior of another class. A subclass should be a true special case of its superclass, not merely a convenient place to reuse code. section 8.2.1
Use inheritance carefully. Deep or wide hierarchies increase cognitive load and can make changes ripple through unexpected subclasses. Composition is usually better for reusable behaviors. section 8.1.2 section 8.2.1
A practical inheritance design should meet these conditions:
- Keep the hierarchy shallow and narrow so its behavior remains easy to reason about. section 8.2.3
- Place specializing subclasses at the leaves and avoid giving them dependencies that would be better represented through composition. section 8.2.3
- Ensure each subclass uses or specializes all of its superclass’s behavior; otherwise, the is-a relationship is doubtful. section 8.2.1 section 8.2.3
- Choose composition for has-a relationships, such as a bicycle having a tire, and inheritance for a carbon-fiber frame being a frame. section 8.2.1
Specializing a bird’s behavior
A Bird can define fly(). Hummingbird(Bird) can override it with faster behavior, while Penguin(Bird) can provide a different result. These subclasses remain recognizable as birds while specializing the same operation.
Compare a rigid inheritance structure with composition that combines related behaviors without forcing every trait into one hierarchy. section 3.5
Listing 3.4. Multiple inheritance providing interface-like behavior
class SpeakMixin: #1
def speak(self):
name = self.__class__.__name__.lower()
print(f'The {name} says, "Hello!"')
class RollOverMixin: #2
def roll_over(self):
print('Did a barrel roll!')
class Dog(SpeakMixin, RollOverMixin): #3
pass
See how Python multiple inheritance combines mixins to provide interface-like behavior through shared methods. section 3.5


















