Skip to content

Inheritance

Reuse code and build relationships between classes.

Inheritance is a mechanism where a new class (derived class or subclass) inherits attributes and methods from an existing class (base class or superclass). This allows you to create a hierarchy of classes that share common functionality while allowing specialization.

Inheritance creates an “is-a” relationship. For example:

  • A Car is-a Vehicle
  • A Dog is-an Animal
  • A Manager is-an Employee
basic_inheritance.py
class Vehicle:
"""Base class (parent/superclass)"""
def __init__(self, brand: str, model: str, year: int):
self.brand = brand
self.model = model
self.year = year
def start(self):
return f"{self.brand} {self.model} started."
def stop(self):
return f"{self.brand} {self.model} stopped."
def get_info(self):
return f"{self.brand} {self.model} ({self.year})"
class Car(Vehicle):
"""Derived class (child/subclass) - inherits from Vehicle"""
def __init__(self, brand: str, model: str, year: int, num_doors: int):
super().__init__(brand, model, year) # Call parent constructor
self.num_doors = num_doors # Additional attribute
def honk(self):
"""New method specific to Car"""
return "Beep beep!"
class Motorcycle(Vehicle):
"""Another derived class"""
def __init__(self, brand: str, model: str, year: int, bike_type: str):
super().__init__(brand, model, year)
self.bike_type = bike_type # Additional attribute
def wheelie(self):
"""New method specific to Motorcycle"""
return "Doing a wheelie!"
# Usage
car = Car("Toyota", "Camry", 2020, 4)
print(car.start()) # Inherited method: "Toyota Camry started."
print(car.honk()) # Car-specific method: "Beep beep!"
print(car.get_info()) # Inherited method: "Toyota Camry (2020)"
motorcycle = Motorcycle("Yamaha", "YZF-R3", 2021, "Sport")
print(motorcycle.start()) # Inherited method: "Yamaha YZF-R3 started."
print(motorcycle.wheelie()) # Motorcycle-specific method: "Doing a wheelie!"
classDiagram
    class Vehicle {
        +brand: str
        +model: str
        +year: int
        +start() str
        +stop() str
        +get_info() str
    }
    
    class Car {
        +num_doors: int
        +honk() str
    }
    
    class Motorcycle {
        +bike_type: str
        +wheelie() str
    }
    
    Vehicle <|-- Car
    Vehicle <|-- Motorcycle

Subclasses can override parent methods to provide specialized behavior:

method_overriding.py
class Vehicle:
def __init__(self, brand: str, model: str, year: int):
self.brand = brand
self.model = model
self.year = year
def start(self):
return f"{self.brand} {self.model} started."
def fuel_type(self):
return "Unknown fuel type"
class Car(Vehicle):
def start(self):
"""Override parent method with specialized behavior"""
return f"{self.brand} {self.model} car started with a roar!"
def fuel_type(self):
"""Override to specify fuel type"""
return "Gasoline or Electric"
class ElectricCar(Car):
def start(self):
"""Further override for electric cars"""
return f"{self.brand} {self.model} silently started (electric motor)"
def fuel_type(self):
"""Override to specify electric"""
return "Electric"
car = Car("Toyota", "Camry", 2020)
print(car.start()) # "Toyota Camry car started with a roar!"
print(car.fuel_type()) # "Gasoline or Electric"
electric_car = ElectricCar("Tesla", "Model 3", 2023)
print(electric_car.start()) # "Tesla Model 3 silently started (electric motor)"
print(electric_car.fuel_type()) # "Electric"

The super() function allows you to call methods from the parent class:

super_example.py
class Employee:
def __init__(self, name: str, employee_id: int):
self.name = name
self.employee_id = employee_id
def get_info(self):
return f"Employee: {self.name} (ID: {self.employee_id})"
class Manager(Employee):
def __init__(self, name: str, employee_id: int, department: str):
super().__init__(name, employee_id) # Call parent __init__
self.department = department
def get_info(self):
"""Extend parent method using super()"""
base_info = super().get_info() # Call parent method
return f"{base_info}, Department: {self.department}"
class Director(Manager):
def __init__(self, name: str, employee_id: int, department: str, budget: float):
super().__init__(name, employee_id, department) # Call Manager's __init__
self.budget = budget
def get_info(self):
"""Further extend using super()"""
manager_info = super().get_info() # Call Manager's get_info
return f"{manager_info}, Budget: ${self.budget:,.2f}"
manager = Manager("Alice", 101, "Engineering")
print(manager.get_info())
# "Employee: Alice (ID: 101), Department: Engineering"
director = Director("Bob", 102, "Engineering", 1000000.0)
print(director.get_info())
# "Employee: Bob (ID: 102), Department: Engineering, Budget: $1,000,000.00"
ecommerce_inheritance.py
class Product:
"""Base class for all products"""
def __init__(self, name: str, price: float, sku: str):
self.name = name
self.price = price
self.sku = sku
def calculate_shipping(self, weight: float) -> float:
"""Base shipping calculation"""
return weight * 2.5 # $2.5 per kg
def get_info(self) -> str:
return f"{self.name} - ${self.price:.2f} (SKU: {self.sku})"
class DigitalProduct(Product):
"""Digital products - no shipping"""
def __init__(self, name: str, price: float, sku: str, download_size: float):
super().__init__(name, price, sku)
self.download_size = download_size # in MB
def calculate_shipping(self, weight: float) -> float:
"""Override - digital products have no shipping cost"""
return 0.0
def get_info(self) -> str:
base_info = super().get_info()
return f"{base_info} - Digital Download ({self.download_size} MB)"
class PhysicalProduct(Product):
"""Physical products with weight"""
def __init__(self, name: str, price: float, sku: str, weight: float):
super().__init__(name, price, sku)
self.weight = weight # in kg
def calculate_shipping(self, weight: float = None) -> float:
"""Override - use product's own weight"""
actual_weight = weight if weight else self.weight
return super().calculate_shipping(actual_weight)
def get_info(self) -> str:
base_info = super().get_info()
return f"{base_info} - Weight: {self.weight} kg"
class FragileProduct(PhysicalProduct):
"""Fragile products need special handling"""
def __init__(self, name: str, price: float, sku: str, weight: float):
super().__init__(name, price, sku, weight)
def calculate_shipping(self, weight: float = None) -> float:
"""Override - add handling fee for fragile items"""
base_shipping = super().calculate_shipping(weight)
handling_fee = 10.0 # Additional $10 for fragile items
return base_shipping + handling_fee
def get_info(self) -> str:
base_info = super().get_info()
return f"{base_info} - FRAGILE"
# Usage
ebook = DigitalProduct("Python Guide", 29.99, "DIG-001", 5.2)
print(ebook.get_info())
print(f"Shipping: ${ebook.calculate_shipping(0):.2f}")
book = PhysicalProduct("Python Book", 39.99, "PHY-001", 0.5)
print(book.get_info())
print(f"Shipping: ${book.calculate_shipping():.2f}")
vase = FragileProduct("Ceramic Vase", 49.99, "FRG-001", 1.2)
print(vase.get_info())
print(f"Shipping: ${vase.calculate_shipping():.2f}")

Python supports multiple inheritance - a class can inherit from multiple parent classes:

multiple_inheritance.py
class Flyable:
def fly(self):
return "Flying through the air"
class Swimmable:
def swim(self):
return "Swimming in water"
class Duck(Flyable, Swimmable):
"""Duck can both fly and swim"""
def __init__(self, name: str):
self.name = name
def quack(self):
return f"{self.name} says quack!"
duck = Duck("Donald")
print(duck.fly()) # From Flyable
print(duck.swim()) # From Swimmable
print(duck.quack()) # Duck's own method

When using multiple inheritance, Python uses Method Resolution Order to determine which method to call:

mro_example.py
class A:
def method(self):
return "A"
class B(A):
def method(self):
return "B"
class C(A):
def method(self):
return "C"
class D(B, C):
pass
d = D()
print(d.method()) # "B" - B comes before C in MRO
print(D.__mro__) # Shows the method resolution order
  • Inheritance creates an “is-a” relationship between classes
  • Subclasses inherit all attributes and methods from parent classes
  • Method overriding allows subclasses to provide specialized behavior
  • super() is used to call parent class methods
  • Multiple inheritance allows a class to inherit from multiple parents
  • MRO determines the order in which methods are resolved in multiple inheritance
  • Use inheritance to reuse code and create specialized classes from general ones

Inheritance is powerful for creating class hierarchies where specialized classes extend and customize the behavior of more general classes.