Inheritance and Polymorphism
# Inheritance and Polymorphism
Welcome to Chapter 19! Inheritance lets you create new classes based on existing ones, and polymorphism lets different classes share a common interface.
---
1. Learning Objectives
- Implement single and multiple inheritance.
-
Override methods and use
super().
- Apply polymorphism, encapsulation, and abstraction.
- Use abstract base classes (ABC).
---
2. Inheritance Basics
```python id="py19ex1" class Animal: def init(self, name, sound): self.name = name self.sound = sound def speak(self): return f"{self.name} says {self.sound}!" def info(self): return f"Animal: {self.name}"
class Dog(Animal): # Dog inherits from Animal def init(self, name, breed): super().init(name, "Woof") # Call parent constructor self.breed = breed def fetch(self): return f"{self.name} fetches the ball! 🎾"
class Cat(Animal): def init(self, name): super().init_(name, "Meow") def purr(self): return f"{self.name} purrs... 😺"
dog = Dog("Buddy", "Labrador") cat = Cat("Luna")
print(dog.speak()) # Buddy says Woof! print(dog.fetch()) # Buddy fetches the ball! print(cat.speak()) # Luna says Meow! print(isinstance(dog, Animal)) # True
python id="py19ex2" class Shape: def area(self): return 0 def describe(self): return f"Shape with area: {self.area()}"
class Circle(Shape): def init(self, radius): self.radius = radius def area(self): # Override parent method return 3.14159 * self.radius ** 2
class Rectangle(Shape): def init_(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height
shapes = [Circle(5), Rectangle(4, 6), Circle(3)] for shape in shapes: print(shape.describe())
python id="py19ex3" class Flyable: def fly(self): return "I can fly! ✈️"
class Swimmable: def swim(self): return "I can swim! 🏊"
class Duck(Animal, Flyable, Swimmable): def init(self, name): super().init(name, "Quack")
duck = Duck("Donald") print(duck.speak()) # Donald says Quack! print(duck.fly()) # I can fly! print(duck.swim()) # I can swim!
# Method Resolution Order (MRO) print(Duck.mro_)
python id="py19ex4" class BankAccount: def init(self, owner, balance): self.owner = owner # Public self.accountid = "ACC123" # Protected (convention) self.balance = balance # Private (name mangling) def getbalance(self): return self._balance def deposit(self, amount): if amount > 0: self.balance += amount
acc = BankAccount("Alice", 1000) print(acc.owner) # Alice — public, OK print(acc.accountid) # ACC123 — works but discouraged # print(acc.balance) # ❌ AttributeError! print(acc.getbalance()) # 1000 — access through method
python id="py19ex5" from abc import ABC, abstractmethod
class Vehicle(ABC): def init_(self, brand): self.brand = brand @abstractmethod def start(self): pass # Must be implemented by subclasses @abstractmethod def stop(self): pass
class Car(Vehicle): def start(self): return f"{self.brand} car engine started! 🚗" def stop(self): return f"{self.brand} car stopped."
class Motorcycle(Vehicle): def start(self): return f"{self.brand} motorcycle revving! 🏍️" def stop(self): return f"{self.brand} motorcycle stopped."
# vehicle = Vehicle("Generic") # ❌ Can't instantiate abstract class! car = Car("Toyota") moto = Motorcycle("Harley") print(car.start()) print(moto.start())
python id="py19ex6" # Same interface, different behavior def printarea(shape): print(f"Area: {shape.area():.2f}")
printarea(Circle(5)) # Area: 78.54 printarea(Rectangle(4, 6)) # Area: 24.00
# Duck typing — Python doesn't care about type, only behavior class Triangle: def _init(self, base, height): self.base = base self.height = height def area(self): return 0.5 * self.base * self.height
printarea(Triangle(6, 4)) # Area: 12.00 — works without inheritance!
``
---
8. MCQs with Answers
Q1: super() calls:
A) Static method B) Parent class method C) Global function D) Class method
Answer: B
Q2: _variable in Python is:
A) Public B) Private (name mangled) C) Protected D) Constant
Answer: B
Q3: Abstract classes can be instantiated: A) Yes B) No Answer: B
Q4: Multiple inheritance MRO follows: A) DFS B) BFS C) C3 Linearization D) Random Answer: C
Q5: Polymorphism means: A) One form B) Many forms C) No form D) Static form Answer: B
Q6: isinstance(obj, Class) checks:
A) Type only B) Type and inheritance C) Memory D) Value
Answer: B
Q7: Encapsulation means: A) Inheriting B) Hiding internal details C) Overriding D) Abstracting Answer: B
Q8: @abstractmethod requires:
A) No implementation B) Implementation in subclass C) Both D) Neither
Answer: B
Q9: Duck typing means: A) Only ducks can be typed B) If it looks like a duck, it's a duck C) Type checking D) Error Answer: B — Python checks behavior, not type.
Q10: issubclass(Dog, Animal) returns:
A) True if Dog inherits Animal B) Always True C) Always False D) Error
Answer: A
---
9. Interview Questions
- 1. What is inheritance? A mechanism where a child class inherits properties and methods from a parent class.
- 2. Diamond problem? Multiple inheritance where two parents have the same method. Python resolves via C3 linearization (MRO).
- 3. What is duck typing? Python doesn't check object type; it checks if the object has the required method/attribute.
- 4. Abstract class vs interface? Python uses ABC for both. Abstract classes can have concrete methods; interfaces (in other languages) typically can't.
- 5. When to use composition vs inheritance? Use inheritance for "is-a" relationships; composition for "has-a" relationships.
---
10. Summary
- Inheritance lets child classes reuse parent class code.
-
super()
calls parent class methods.
- Method overriding lets children customize inherited behavior.
-
Encapsulation hides internal state (protected
,__private`).
- Abstraction with ABC defines interfaces that subclasses must implement.
- Polymorphism lets different classes be used through a common interface.
---
11. Next Chapter Recommendation
In Chapter 20: Python Iterators and Generators, you'll learn lazy evaluation and memory-efficient data processing! 🚀