Requires every subclass instance to replace its superclass instance without making the program incorrect. The replacement should preserve the superclass interface and basic outcomes, even when implementation details differ. section 8.2.2
When specialization breaks substitution
A Snail subclass of Slug adds a required shell_size argument. Code that creates a Slug can no longer replace it with a Snail without changing its call. A snail has a shell, so composition may fit better than inheritance. section 8.2.2
Check a subclass by asking:
- Does it preserve inherited method signatures and behavior? section 8.2.2
- Does it fulfill the same role as every other class in the hierarchy? section 8.2.2
- Does it avoid unused behavior, no-op overrides, or exceptions that invalidate superclass expectations? section 8.2.3
Listing 8.1. A subclass that breaks substitutability
class Slug:
def __init__(self, name):
self.name = name
def crawl(self):
print('slime trail!')
class Snail(Slug): #1
def __init__(self, name, shell_size): #2
super().__init__(name)
self.name = name
self.shell_size = shell_size
def race(gastropod_one, gastropod_two):
gastropod_one.crawl()
gastropod_two.crawl()
race(Slug('Geoffrey'), Slug('Ramona')) #3
race(Snail('Geoffrey'), Snail('Ramona')) #4
Inspect the Slug and Snail example to see how a changed constructor prevents direct substitution. section 8.2.2




