Daily Tech Brief

Top startup stories in your inbox

Subscribe Free

Β© 2026 rakrisi Daily

Inheritance - Code Reuse and Hierarchy

Inheritance: Code Reuse and Hierarchy

Welcome to Inheritance! Think of it as family inheritance - child classes automatically get properties and methods from their parent classes, but can also add their own unique features.

What is Inheritance?

Inheritance allows you to create new classes based on existing classes. The new class (child) inherits all the attributes and methods of the existing class (parent), and can add new features or modify existing ones.

Basic Inheritance

# Parent class (base class)
class Animal:
    def __init__(self, name, species):
        self.name = name
        self.species = species

    def make_sound(self):
        return "Some generic animal sound"

    def eat(self, food):
        return f"{self.name} eats {food}"

# Child class (derived class)
class Dog(Animal):  # Inherits from Animal
    def __init__(self, name, breed):
        super().__init__(name, "Dog")  # Call parent constructor
        self.breed = breed

    def make_sound(self):  # Override parent method
        return "Woof!"

    def fetch(self):  # Add new method
        return f"{self.name} fetches the ball!"

# Test inheritance
generic_animal = Animal("Generic", "Unknown")
dog = Dog("Buddy", "Golden Retriever")

print(generic_animal.make_sound())  # "Some generic animal sound"
print(dog.make_sound())            # "Woof!" (overridden)
print(dog.eat("dog food"))         # "Buddy eats dog food" (inherited)
print(dog.fetch())                 # "Buddy fetches the ball!" (new)

The super() Function

Calling Parent Methods

class Vehicle:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

    def start_engine(self):
        return f"{self.make} {self.model} engine started"

    def get_info(self):
        return f"{self.year} {self.make} {self.model}"

class Car(Vehicle):
    def __init__(self, make, model, year, num_doors):
        super().__init__(make, model, year)  # Call parent __init__
        self.num_doors = num_doors

    def start_engine(self):
        # Call parent method and add extra behavior
        base_message = super().start_engine()
        return f"{base_message} - Car with {self.num_doors} doors ready to go!"

    def get_info(self):
        # Extend parent method
        base_info = super().get_info()
        return f"{base_info} ({self.num_doors} doors)"

# Test
car = Car("Toyota", "Camry", 2020, 4)
print(car.start_engine())
print(car.get_info())

Multiple Inheritance with super()

class Engine:
    def __init__(self, horsepower):
        self.horsepower = horsepower

    def get_power(self):
        return f"{self.horsepower} HP"

class Transmission:
    def __init__(self, type_):
        self.type = type_

    def get_transmission_info(self):
        return f"{self.type} transmission"

class SportsCar(Engine, Transmission):
    def __init__(self, make, model, horsepower, transmission_type):
        Engine.__init__(self, horsepower)          # Call Engine.__init__
        Transmission.__init__(self, transmission_type)  # Call Transmission.__init__
        self.make = make
        self.model = model

    def get_specs(self):
        return f"{self.make} {self.model}: {self.get_power()}, {self.get_transmission_info()}"

# Test multiple inheritance
sports_car = SportsCar("Ferrari", "488", 661, "Automatic")
print(sports_car.get_specs())

Method Overriding

Overriding Parent Methods

class Shape:
    def __init__(self, name):
        self.name = name

    def area(self):
        raise NotImplementedError("Subclasses must implement area()")

    def perimeter(self):
        raise NotImplementedError("Subclasses must implement perimeter()")

    def describe(self):
        return f"This is a {self.name}"

class Rectangle(Shape):
    def __init__(self, width, height):
        super().__init__("Rectangle")
        self.width = width
        self.height = height

    def area(self):  # Override abstract method
        return self.width * self.height

    def perimeter(self):  # Override abstract method
        return 2 * (self.width + self.height)

class Circle(Shape):
    def __init__(self, radius):
        super().__init__("Circle")
        self.radius = radius

    def area(self):
        return 3.14159 * self.radius ** 2

    def perimeter(self):
        return 2 * 3.14159 * self.radius

# Test
shapes = [
    Rectangle(5, 3),
    Circle(4)
]

for shape in shapes:
    print(f"{shape.describe()}")
    print(f"Area: {shape.area()}")
    print(f"Perimeter: {shape.perimeter()}")
    print()

Using super() in Overridden Methods

class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

    def get_info(self):
        return f"Employee: {self.name}, Salary: ${self.salary}"

    def work(self):
        return f"{self.name} is working"

class Manager(Employee):
    def __init__(self, name, salary, department):
        super().__init__(name, salary)
        self.department = department

    def get_info(self):
        # Extend parent method
        base_info = super().get_info()
        return f"{base_info}, Department: {self.department}"

    def work(self):
        # Modify parent method
        base_work = super().work()
        return f"{base_work} as a manager overseeing {self.department}"

class Developer(Employee):
    def __init__(self, name, salary, programming_language):
        super().__init__(name, salary)
        self.programming_language = programming_language

    def work(self):
        return f"{self.name} is coding in {self.programming_language}"

# Test
employees = [
    Manager("Alice", 80000, "Engineering"),
    Developer("Bob", 70000, "Python"),
    Employee("Charlie", 50000)
]

for emp in employees:
    print(emp.get_info())
    print(emp.work())
    print()

Abstract Base Classes

Using abc Module

from abc import ABC, abstractmethod

class PaymentProcessor(ABC):
    def __init__(self, amount):
        self.amount = amount

    @abstractmethod
    def process_payment(self):
        """Must be implemented by subclasses."""
        pass

    @abstractmethod
    def validate_payment(self):
        """Must be implemented by subclasses."""
        pass

    def get_receipt(self):
        return f"Payment of ${self.amount} processed"

class CreditCardProcessor(PaymentProcessor):
    def __init__(self, amount, card_number, expiry_date):
        super().__init__(amount)
        self.card_number = card_number
        self.expiry_date = expiry_date

    def validate_payment(self):
        # Validate card number format
        if not self.card_number.replace(" ", "").isdigit():
            raise ValueError("Invalid card number")
        return True

    def process_payment(self):
        self.validate_payment()
        # Process credit card payment
        return f"Processed ${self.amount} via credit card ****{self.card_number[-4:]}"

class PayPalProcessor(PaymentProcessor):
    def __init__(self, amount, email):
        super().__init__(amount)
        self.email = email

    def validate_payment(self):
        if "@" not in self.email:
            raise ValueError("Invalid PayPal email")
        return True

    def process_payment(self):
        self.validate_payment()
        return f"Processed ${self.amount} via PayPal account {self.email}"

# Test
processors = [
    CreditCardProcessor(100, "4111 1111 1111 1111", "12/25"),
    PayPalProcessor(50, "user@example.com")
]

for processor in processors:
    try:
        result = processor.process_payment()
        print(result)
        print(processor.get_receipt())
    except ValueError as e:
        print(f"Payment failed: {e}")
    print()

Multiple Inheritance

Diamond Problem and Method Resolution Order

class A:
    def method(self):
        return "Method from A"

class B(A):
    def method(self):
        return "Method from B"

class C(A):
    def method(self):
        return "Method from C"

class D(B, C):  # Multiple inheritance
    pass

# Test method resolution order
d = D()
print(d.method())  # "Method from B" (B comes first in inheritance list)
print(D.__mro__)   # Method Resolution Order: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

Practical Multiple Inheritance

class LoggerMixin:
    """Mixin class for logging functionality."""
    def log(self, message):
        print(f"[{self.__class__.__name__}] {message}")

class SerializableMixin:
    """Mixin class for serialization."""
    def to_dict(self):
        return self.__dict__.copy()

    def from_dict(self, data):
        self.__dict__.update(data)

class User(LoggerMixin, SerializableMixin):
    def __init__(self, name, email):
        self.name = name
        self.email = email
        self.log(f"User {name} created")

    def update_email(self, new_email):
        old_email = self.email
        self.email = new_email
        self.log(f"Email changed from {old_email} to {new_email}")

# Test mixins
user = User("Alice", "alice@example.com")
user.update_email("alice@newdomain.com")

# Serialization
user_data = user.to_dict()
print("Serialized:", user_data)

# Create new user from data
new_user = User("", "")
new_user.from_dict(user_data)
print(f"Deserialized: {new_user.name}, {new_user.email}")

isinstance() and issubclass()

Type Checking with Inheritance

class Animal:
    pass

class Dog(Animal):
    pass

class Cat(Animal):
    pass

class Labrador(Dog):
    pass

# Test inheritance relationships
animals = [Animal(), Dog(), Cat(), Labrador()]

for animal in animals:
    print(f"{animal.__class__.__name__}:")
    print(f"  isinstance(animal, Animal): {isinstance(animal, Animal)}")
    print(f"  isinstance(animal, Dog): {isinstance(animal, Dog)}")
    print()

print("Class relationships:")
print(f"issubclass(Dog, Animal): {issubclass(Dog, Animal)}")
print(f"issubclass(Cat, Animal): {issubclass(Cat, Animal)}")
print(f"issubclass(Labrador, Dog): {issubclass(Labrador, Dog)}")
print(f"issubclass(Labrador, Animal): {issubclass(Labrador, Animal)}")
print(f"issubclass(Animal, Dog): {issubclass(Animal, Dog)}")

Practical Examples

Example 1: Employee Management System

from abc import ABC, abstractmethod

class Employee(ABC):
    def __init__(self, name, employee_id, salary):
        self.name = name
        self.employee_id = employee_id
        self.salary = salary

    @abstractmethod
    def calculate_payroll(self):
        pass

    def get_info(self):
        return f"{self.name} (ID: {self.employee_id}) - ${self.salary}/year"

class SalariedEmployee(Employee):
    def calculate_payroll(self):
        # Monthly salary
        return self.salary / 12

class HourlyEmployee(Employee):
    def __init__(self, name, employee_id, hourly_rate, hours_worked):
        super().__init__(name, employee_id, 0)  # Salary not used
        self.hourly_rate = hourly_rate
        self.hours_worked = hours_worked

    def calculate_payroll(self):
        return self.hourly_rate * self.hours_worked

class Manager(SalariedEmployee):
    def __init__(self, name, employee_id, salary, bonus_percentage):
        super().__init__(name, employee_id, salary)
        self.bonus_percentage = bonus_percentage

    def calculate_payroll(self):
        base_pay = super().calculate_payroll()
        bonus = base_pay * (self.bonus_percentage / 100)
        return base_pay + bonus

# Test
employees = [
    SalariedEmployee("Alice", "001", 60000),
    HourlyEmployee("Bob", "002", 25, 160),
    Manager("Charlie", "003", 80000, 10)
]

for emp in employees:
    print(f"{emp.get_info()}")
    print(f"Monthly payroll: ${emp.calculate_payroll():.2f}")
    print()

Example 2: Game Character System

class Character:
    def __init__(self, name, health, attack_power):
        self.name = name
        self.health = health
        self.max_health = health
        self.attack_power = attack_power
        self.level = 1

    def attack(self, target):
        damage = self.attack_power
        target.take_damage(damage)
        return f"{self.name} attacks {target.name} for {damage} damage!"

    def take_damage(self, damage):
        self.health -= damage
        if self.health <= 0:
            self.health = 0
            return f"{self.name} has been defeated!"
        return f"{self.name} takes {damage} damage, {self.health} health remaining"

    def heal(self, amount):
        old_health = self.health
        self.health = min(self.max_health, self.health + amount)
        healed = self.health - old_health
        return f"{self.name} heals for {healed} health"

class Warrior(Character):
    def __init__(self, name):
        super().__init__(name, health=150, attack_power=20)
        self.rage = 0

    def attack(self, target):
        # Warriors build rage
        self.rage = min(100, self.rage + 20)
        return super().attack(target)

    def special_attack(self, target):
        if self.rage >= 50:
            damage = self.attack_power * 2
            self.rage -= 50
            target.take_damage(damage)
            return f"{self.name} unleashes a powerful attack for {damage} damage!"
        return f"{self.name} doesn't have enough rage for special attack"

class Mage(Character):
    def __init__(self, name):
        super().__init__(name, health=100, attack_power=15)
        self.mana = 100
        self.max_mana = 100

    def attack(self, target):
        if self.mana >= 10:
            self.mana -= 10
            return super().attack(target)
        return f"{self.name} doesn't have enough mana to attack"

    def cast_spell(self, target):
        if self.mana >= 30:
            self.mana -= 30
            damage = self.attack_power * 3
            target.take_damage(damage)
            return f"{self.name} casts a fireball for {damage} damage!"
        return f"{self.name} doesn't have enough mana to cast spell"

    def meditate(self):
        self.mana = min(self.max_mana, self.mana + 50)
        return f"{self.name} meditates and restores mana"

# Test
warrior = Warrior("Conan")
mage = Mage("Merlin")

print("Battle begins!")
print(warrior.attack(mage))
print(mage.cast_spell(warrior))
print(warrior.special_attack(mage))
print(mage.meditate())
print(mage.attack(warrior))

Example 3: File System Hierarchy

from abc import ABC, abstractmethod
import os
from pathlib import Path

class FileSystemItem(ABC):
    def __init__(self, name, parent=None):
        self.name = name
        self.parent = parent
        self.created_time = "2024-01-01"  # Simplified

    @abstractmethod
    def get_size(self):
        pass

    def get_path(self):
        if self.parent:
            return f"{self.parent.get_path()}/{self.name}"
        return self.name

class File(FileSystemItem):
    def __init__(self, name, size, parent=None):
        super().__init__(name, parent)
        self.size = size

    def get_size(self):
        return self.size

    def get_extension(self):
        return Path(self.name).suffix

class Directory(FileSystemItem):
    def __init__(self, name, parent=None):
        super().__init__(name, parent)
        self.children = []

    def add_item(self, item):
        item.parent = self
        self.children.append(item)

    def get_size(self):
        return sum(child.get_size() for child in self.children)

    def list_contents(self):
        return [child.name for child in self.children]

    def find_files_by_extension(self, extension):
        files = []
        for child in self.children:
            if isinstance(child, File) and child.get_extension() == extension:
                files.append(child)
            elif isinstance(child, Directory):
                files.extend(child.find_files_by_extension(extension))
        return files

# Test
root = Directory("root")
documents = Directory("documents")
pictures = Directory("pictures")

root.add_item(documents)
root.add_item(pictures)

# Add files
documents.add_item(File("resume.pdf", 2048))
documents.add_item(File("letter.docx", 1024))
pictures.add_item(File("vacation.jpg", 5120))
pictures.add_item(File("family.png", 3072))

print(f"Root directory size: {root.get_size()} bytes")
print(f"Documents: {documents.list_contents()}")
print(f"Picture files: {[f.name for f in pictures.find_files_by_extension('.jpg')]}")

# Find all PDF files
pdf_files = root.find_files_by_extension('.pdf')
print(f"PDF files: {[f.name for f in pdf_files]}")

Practice Exercises

Exercise 1: Vehicle Hierarchy

Create a vehicle inheritance hierarchy:

  • Base Vehicle class
  • Car, Truck, Motorcycle subclasses
  • Each with specific attributes and methods
  • Demonstrate polymorphism

Exercise 2: Shape Calculator

Build a shape calculation system:

  • Abstract Shape base class
  • Circle, Rectangle, Triangle subclasses
  • Implement area and perimeter calculations
  • Add shape-specific methods

Exercise 3: Employee Payroll System

Create an employee management system:

  • Base Employee class
  • Manager, Developer, Intern subclasses
  • Different payroll calculation methods
  • Bonus systems for managers

Exercise 4: Game Item System

Build a game item inheritance system:

  • Base Item class
  • Weapon, Armor, Consumable subclasses
  • Different behaviors for each type
  • Inventory management

Exercise 5: Document Management

Create a document management system:

  • Base Document class
  • PDF, WordDocument, Spreadsheet subclasses
  • Different processing methods
  • Search and filter functionality

Summary

Inheritance enables code reuse and creates class hierarchies:

Basic Inheritance:

class Child(Parent):
    def __init__(self, ...):
        super().__init__(...)
        # Child-specific initialization

Method Overriding:

class Child(Parent):
    def some_method(self):
        # Override parent method
        return "Child implementation"

Abstract Base Classes:

from abc import ABC, abstractmethod

class AbstractClass(ABC):
    @abstractmethod
    def required_method(self):
        pass

Multiple Inheritance:

class Child(Parent1, Parent2):
    # Inherits from multiple parents
    pass

Key Concepts:

  • super() calls parent methods
  • Method Resolution Order (MRO) for multiple inheritance
  • Abstract methods must be implemented by subclasses
  • isinstance() and issubclass() for type checking

When to Use Inheritance:

  • β€œIs-a” relationships (Car is a Vehicle)
  • Code reuse from parent classes
  • Polymorphic behavior
  • Creating class hierarchies

Next: Polymorphism - same interface, different implementations! 🎭