Goal
You’ll be able to use inheritance to build a class based on an existing one, and understand what polymorphism genuinely means in practice, not just as an abstract term.
Learn
Inheritance lets a new class reuse and extend an existing class’s behavior, rather than duplicating code:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound."
class Dog(Animal):
def speak(self):
return f"{self.name} says woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says meow!" Dog(Animal) means Dog inherits from Animal — it automatically gets Animal’s __init__ (no need to redefine it), while overriding the speak method with its own specific version.
This overriding is exactly what polymorphism means in practice: different classes providing their own specific version of the same-named method, callable in exactly the same way, letting code work generically with any of them without needing to know the specific type in advance:
animals = [Dog("Rex"), Cat("Whiskers")]
for animal in animals:
print(animal.speak()) # each calls its OWN version automatically
# "Rex says woof!"
# "Whiskers says meow!" This loop doesn’t need to know or check whether each animal is specifically a Dog or a Cat — it just calls .speak() on each one, and Python automatically uses whichever specific version that object’s actual class defines. This is genuinely useful for writing flexible code that works correctly with many different related types without needing special-case handling for each one.
Decision Task
You add a new class Bird(Animal) with its own speak() method, without changing the loop from the example above at all. Before reading on: does the existing loop iterating over a list of animals need any modification to correctly handle Bird objects too?
Show Answer
No modification needed at all — this is exactly the practical benefit of polymorphism. The loop just calls .speak() on whatever object it encounters; Python automatically uses that specific object’s own speak() method, whether it’s a Dog, Cat, or newly-added Bird, without the loop needing to know or check the specific type in advance.
Common Mistake
Writing explicit type-checking code (like if isinstance(animal, Dog): ... elif isinstance(animal, Cat): ...) to manually handle each type differently, when polymorphism through method overriding would let each class handle its own specific behavior automatically. This defeats much of the actual benefit of inheritance and polymorphism, recreating manually what Python already does automatically when each subclass defines its own version of a shared method name.
Practice Questions
1. Write a class Cylinder that inherits from a class Shape (assume Shape exists already), adding nothing new — just demonstrating basic inheritance syntax.
Show Answer
class Cylinder(Shape):\n pass
2. What does it mean for a subclass to “override” a method from its parent class?
Show Answer
The subclass defines its own version of a method with the same name as the parent class’s version, and that version is used instead whenever called on an object of the subclass.
3. Given the Animal/Dog/Cat example, if you create a plain Animal object (not Dog or Cat) and call .speak() on it, what would it return?
Show Answer
“[name] makes a sound.” — the base Animal class’s own speak() method, since a plain Animal object has no override.
4. True or False: a subclass must redefine every method from its parent class, even ones it doesn’t want to change.
Show Answer
False — a subclass automatically inherits all of its parent’s methods and attributes; it only needs to define a method itself if it wants to override that specific one with different behavior.
5. What real practical benefit does polymorphism provide for code like a loop calling .speak() on a list of different animal types?
Show Answer
The loop can work generically with any animal subclass without needing to know or check its specific type, since each object automatically uses its own correct version of the shared method name.
Try It Yourself
Without looking back, add a new class Cow(Animal) with its own speak() method returning “[name] says moo!” — using the Animal base class from this lesson’s example.
Show Answer
class Cow(Animal):\n def speak(self):\n return f"{self.name} says moo!" — following the exact same override pattern as Dog and Cat.
Quick Check
1. What does inheritance let a new class do?
Show Answer
Reuse and extend an existing class’s behavior, rather than duplicating code.
2. What is method overriding?
Show Answer
A subclass defining its own version of a method with the same name as its parent class’s version.
3. What does polymorphism mean in practice, as covered in this lesson?
Show Answer
Different classes providing their own version of a same-named method, callable the same way, letting code work generically without knowing the specific type.
4. Does a subclass need to redefine every method from its parent class?
Show Answer
No — it automatically inherits everything, only overriding what it specifically needs to change.
5. Class Dog(Animal) — what does the (Animal) part indicate?
Show Answer
That Dog inherits from Animal.