OOP Pillars: Inheritance, Polymorphism & Encapsulation
Inheritance lets a class reuse and extend another class. Polymorphism lets the same method name behave differently across objects. Encapsulation groups data with the methods that protect and control it, improving reliability and reducing accidental misuse.
Learning Objectives
- 11.4.2.2 Explain the concept of inheritance with examples
- 11.4.2.1 Explain the concept of polymorphism with examples
- 11.4.2.x Explain the concept of encapsulation with examples
Conceptual Anchor
The Family Tree Analogy
Inheritance: A child inherits traits from a parent, but can also add new traits or change inherited ones. Polymorphism: Different family members may respond to the same request in different ways, even though the request is the same. Encapsulation: A family may share an address and surname, but private details are kept within the household and accessed through trusted rules.
Rules & Theory
Inheritance
In Cambridge terminology, the base class, parent class, or superclass is the existing class being extended. The derived class, child class, or subclass is the new class that inherits features from it.
Inheritance is used when the relationship is is-a, for example a Car is a Vehicle. The subclass automatically receives accessible attributes and methods from the superclass, and it can add extra features or override inherited methods.
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name} is eating.")
class Dog(Animal):
def bark(self):
print("Woof!")
d = Dog("Buddy")
d.eat()
d.bark() super()
Use super().__init__() inside a child class to call the parent constructor. This is important when the parent class sets up shared state that all subclasses need.
Polymorphism
Polymorphism means one interface can be used with many object types. In Python, the most common form in AS/A Level code is run-time polymorphism through method overriding and duck typing: if an object has the required method, it can be used.
Compile-time polymorphism refers to method overloading in some languages, where multiple methods have the same name but different parameter lists. Python does not support traditional compile-time overloading in the same way; instead, it usually uses default parameters, variable-length arguments, or different method names.
Run-time polymorphism occurs when a subclass provides its own version of a method from the parent class. Python decides which version to run at execution time, based on the actual object.
class Cat(Animal):
def speak(self):
return "Meow"
class Dog(Animal):
def speak(self):
return "Woof"
animals = [Cat("Kitty"), Dog("Buddy"), Cat("Luna")]
for animal in animals:
print(f"{animal.name} says {animal.speak()}")Encapsulation
Encapsulation means hiding an object's internal data and forcing access through methods. In Python, attributes with no underscore are public, a single underscore such as _balance is a protected convention meaning "internal use", and a double underscore such as __balance triggers name mangling to make direct access less likely.
Name mangling changes __balance inside the class to a form like _BankAccount__balance. This is not true security, but it reduces accidental access and helps enforce a class interface. Good design uses getters and setters, or the @property decorator, to control reading and updating values safely.
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance
@property
def balance(self):
return self.__balance
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
acc = BankAccount("Amina", 100)
acc.deposit(50)
acc.withdraw(30)
print(acc.balance)Worked Examples
1 Shapes Hierarchy
import math
class Shape:
def area(self):
pass
class Rectangle(Shape):
def __init__(self, w, h):
self.w = w
self.h = h
def area(self):
return self.w * self.h
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
return math.pi * self.r ** 2
shapes = [Rectangle(10, 5), Circle(7)]
for s in shapes:
print(f"Area: {s.area():.2f}")2 Game Characters
class Character:
def __init__(self, name):
self.name = name
self.health = 100
def attack(self):
print("Basic attack!")
class Warrior(Character):
def attack(self):
print(f"{self.name} swings a sword!")
class Mage(Character):
def attack(self):
print(f"{self.name} casts a fireball!")
hero = Warrior("Arthur")
wizard = Mage("Merlin")
hero.attack()
wizard.attack()3 Bank Account Encapsulation
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance
def get_balance(self):
return self.__balance
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def withdraw(self, amount):
if 0 <= amount <= self.__balance:
self.__balance -= amount
acct = BankAccount("Noah", 200)
acct.withdraw(50)
print(acct.get_balance())Pitfalls & Common Errors
Overriding Mistakes
If you misspell an overridden method name, Python treats it as a new method. The parent method will still run when the object is used polymorphically.
Forgetting super().__init__
If a child class defines its own __init__, it does not automatically call the parent constructor. You must call it manually or inherited attributes may not exist.
Type Checking vs Polymorphism
Using isinstance() or long if/elif chains before calling methods weakens polymorphism. Prefer a shared interface and let each object decide its own behaviour.
Encapsulation Misconceptions
Do not assume __ makes data truly secure. Name mangling only discourages direct access; it does not encrypt the value. Also avoid reading or changing attributes directly when getter and setter methods are provided, because that bypasses validation and can break class rules.
Graded Tasks
Describe the purpose of encapsulation. [2 marks]
State the difference between a superclass and a subclass, using Cambridge terminology. [2 marks]
Trace the output of a program that creates a parent class and two subclasses that override the same method. Explain why each output line is different. [4 marks]
Design a BankAccount class for a school savings system. Include an encapsulated balance, deposit and withdraw methods, and explain why direct access to the balance should be avoided. [6 marks]