Python

P
PythonHub
Progress 0%

Python

  • Home
  • History of Python
  • Applications of Python
  • Introduction To Python
    • What is Python
    • Character Set
    • Tokens in Python
    • Python Execution Mode
    • Variable And Identifiers
    • Data Types in Python
    • Operators And Expressions
    • Constants in Python
    • Assignment Statement
    • Input / Output in Python
    • Simple Python Scripts
    • Namespace in Python
    • 📝 Assignments
  • Operators in Python
    • Arithmetic Operators
    • Assignment Operators
    • Shorthand Assignment Operators
    • Relational Operators
    • Logical Operators
    • Bitwise Operators
    • Special Operators
    • 📝 Assignments
  • Input Output in Python
    • Accept Input
    • Output Formatting
    • 📝 Assignments
  • Conditional Statement
    • Decision Making
    • if Statement
    • IF-ELSE STATEMENT
    • IF-ELSE LADDER
    • NESTED IF-ELSE
    • Short Hand IF-ELSE
    • 📝 Assignments
  • Loops
    • Introduction to Loops
    • While Loop
    • Nested While Loop
    • 📝 While Loop Assignments
    • For Loop
    • For Loop Examples
    • Nested For Loop
    • Nested For Loop Examples
    • Infinite While Loops
    • Infinite For Loops
    • Break, Continue and Else in Loops
    • Difference Between For and While Loop
    • For Each Loop
    • 📝 For Each Assignments
    • 📝 All Loops Assignments
  • List
    • List in Python
    • Access List Elements
    • List Functions
    • Iterate (Loop) List
    • List Comprehension
    • 📝 Assignments
  • Tuple
    • Tuple in Python
    • Access Tuple Elements
    • Tuple Functions
    • Iterate (Loop) Tuple
    • Unpack Tuple
    • Tuple Comprehension
    • 📝 Assignments
  • Set
    • Set in Python
    • Access Set Elements
    • Set Methods
    • Iterate (Loop) Set
    • Pack/Unpack Set
    • Set Comprehension
    • 📝 Assignments
  • Dictionary
    • Dictionary
    • Access Dictionary Items
    • Dictionary Methods
    • Iterate (Loop) Dictionary
    • Formatting Dictionaries
    • Nested Dictionaries
    • Dictionary Comprehension
    • 📝 Assignments
  • Diff List Tuple Set Dictionary
    • List vs Tuple
    • List vs Set
    • List vs Dictionary
    • Tuple vs Set
    • Tuple vs Dictionary
    • Dictionary vs Set
    • 📝 Assignments
  • Exception
    • Error vs Exception
    • Types of Exception
    • Exception Handling
    • User Defined Exception
    • Logging Exception
    • 📝 Assignments
  • Functions
    • Introduction to Functions
    • Modular Programming
    • Types of Functions
    • Inbuilt Functions
    • Need For User-Defined Function
    • Elements of User Defined Function
    • Function Arguments
    • Nesting of Functions
    • Recursion
    • Global Local and Non Local
    • Python Lambda Functions
    • 📝 Assignments
  • Python Module
    • Introduction to Module
    • Inbuilt Modules in Python
    • User Defined Module
    • 📝 Assignments
  • File Handling
    • Introduction to Files
    • Create File
    • Read Files
    • Write to File
    • Rename File
    • Copy File
    • Move File
    • List Files in Directory
    • Binary Files
    • Zipping and Unzipping Files
    • 📝 Assignments
  • Strings
    • Basics of Strings
    • String Special Operators
    • String Formatting Operators
    • String Methods
    • 📝 Assignments
  • Regular Expressions
  • Python OOPS
    • Basics of Object Oriented
    • What are Classes and Objects?
    • Creating Class and Object
    • OOP vs Procedural Programming
    • Difference Between Classes and Objects
    • Constructors
    • Destructor
    • Built Class Methods and Attributes
    • Class and Instance Variables
    • Inheritance in Python
    • Single Inheritance
    • Multiple Inheritance
    • Multilevel Inheritance
    • Hierarchical Inheritance
    • Hybrid Inheritance
    • Abstraction
    • Method Overriding
    • Abstract Method
    • Interfaces in Python
    • Abstract Class vs Interface
    • Public, Private and Protected
    • Overloading vs Overriding
    • Inheritance vs Composition
    • Encapsulation
    • Polymorphism
    • Inner Classes
    • 📝 Assignments
  • Advanced Python
    • Iterator in Python
    • Generator in Python
    • Decorator in Python
    • Type Hints in Python
    • Async/Await Programming
    • Dataclasses in Python
    • Context Managers in Python
    • Property Decorator in Python
    • __slots__ in Python
    • Enums in Python
    • Walrus Operator in Python
    • Match-Case in Python
    • 📝 Assignments
  • Python Standard Library
    • Collections Module
    • Itertools Module
    • Functools Module
    • Datetime Module
    • JSON Module
    • OS Module
    • Sys Module
    • Random Module
    • Math Module
    • 📝 Assignments
  • Python Testing
    • Unit Testing in Python
    • Pytest Framework
    • Mocking in Python
    • 📝 Assignments
  • Python Best Practices
    • PEP 8 Style Guide
    • Docstrings in Python
    • Logging in Python
    • Code Optimization Tips
    • Debugging Techniques
    • 📝 Assignments
  • MySQL Database in Python
    • Introduction to MySQL with Python
    • DBMS vs File System
    • Connecting to MySQL Database
    • Create Database in MySQL
    • Create Table in MySQL
    • Insert Data in MySQL
    • Insert Multiple Rows
    • Select Data from MySQL
    • WHERE Clause in MySQL
    • Update Data in MySQL
    • Delete Data from MySQL
    • Parameterized Queries
    • Transaction Management
    • Error Handling
    • Connection Pooling
    • MySQL Drivers Guide
    • Joins in MySQL
    • Aggregation Functions
    • Backup MySQL Database
    • Best Practices
    • 📝 Assignments
  • MySQL Database Operations
    • SELECT Statement
    • MySQL Operators
    • DDL Statements
    • DML Statements
    • Subqueries
    • JOIN Operations
    • Aggregation
    • Case Study
    • 📝 Assignments
  • Graphics in Python
  • Threads in Python
    • Introduction to Threads
    • Process vs Threads
    • Concurrent Programming & GIL
    • Uses of Threads
    • Creating Threads
    • Single Tasking
    • Multi Tasking
    • Thread Synchronization
    • 📝 Assignments
  • Interview Questions & Answers
  • Python Case Studies
  • Multiple Choice Questions
  • 📝 Practice Problems
Get in Touch
  • tech2dsm@gmail.com

© Sankalan Data Tech

Python Language Interactive Tutorial

Python: Hierarchical Inheritance

Python Hierarchical Inheritance - Complete Guide

Learn how one parent class can have many child classes in Python.

Created by Sankalan Data Tech Team Verified
Data Engineers, Analysts, Scientists & Trainers
Created by experienced Python developers, data engineers, and data scientists to make programming easy through practical examples, real-world experience, and clear explanations.
On this page:
  • What is Hierarchical Inheritance?
  • One Parent, Many Children
  • How Hierarchical Inheritance Works
  • Sharing Common Features
  • Each Child Has Its Own Identity
  • Working with Constructors
  • Real-World Examples
  • Best Practices
  • Try It Yourself
  • Quick Quiz
  • Frequently Asked Questions
Share this tutorial:
Twitter LinkedIn Facebook WhatsApp Reddit Telegram Email Copy Link
What You'll Learn Here
  • What is hierarchical inheritance — one parent class with many children
  • How it works — understanding the one-to-many relationship
  • Sharing common features — how children reuse parent code
  • Each child is unique — adding specific features to each child
  • Constructors — initializing parent and child classes
  • Real-world use — practical examples you can use

What is Hierarchical Inheritance?

Hierarchical inheritance is a type of inheritance where a single parent class is inherited by many child classes. Think of it like a family tree where one parent has many children. Each child gets the parent's traits, but each child is also unique and can have its own special qualities.

Imagine a school teacher who teaches many students. All students learn the same basic lessons from the teacher (parent class), but each student has their own personality, interests, and skills (child classes). This is exactly how hierarchical inheritance works in Python.

This is different from multilevel inheritance, where you have a chain like Grandparent → Parent → Child. In hierarchical inheritance, you have one parent and many children directly under it.

💡 Key concept: Hierarchical inheritance is like a tree — one parent class at the root, with many child classes branching out from it. Each child inherits the parent's features but can also have its own unique features.

One Parent, Many Children

1

Understanding the One-to-Many Relationship

In hierarchical inheritance, you have one parent class that is the base for many child classes. Each child class inherits everything from the parent, but each child can also add its own methods and attributes.

# Hierarchical inheritance - One parent, many children

# Parent class (the base)
class Animal:
    """The parent class - common to all animals"""
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def eat(self):
        return f"{self.name} is eating"
    
    def sleep(self):
        return f"{self.name} is sleeping"
    
    def sound(self):
        return f"{self.name} makes a sound"

# Child class 1 - Dog
class Dog(Animal):
    """Dog is a child of Animal"""
    
    def sound(self):
        return f"{self.name} says Woof!"
    
    def fetch(self):
        return f"{self.name} is fetching the ball"

# Child class 2 - Cat
class Cat(Animal):
    """Cat is a child of Animal"""
    
    def sound(self):
        return f"{self.name} says Meow!"
    
    def purr(self):
        return f"{self.name} is purring"

# Child class 3 - Bird
class Bird(Animal):
    """Bird is a child of Animal"""
    
    def sound(self):
        return f"{self.name} says Chirp!"
    
    def fly(self):
        return f"{self.name} is flying"

# Creating objects
print("=== DOG ===")
dog = Dog("Buddy", 3)
print(dog.eat())     # Buddy is eating (from parent)
print(dog.sound())   # Buddy says Woof! (overridden)
print(dog.fetch())   # Buddy is fetching the ball (specific to Dog)

print("\n=== CAT ===")
cat = Cat("Whiskers", 2)
print(cat.eat())     # Whiskers is eating (from parent)
print(cat.sound())   # Whiskers says Meow! (overridden)
print(cat.purr())    # Whiskers is purring (specific to Cat)

print("\n=== BIRD ===")
bird = Bird("Tweety", 1)
print(bird.eat())    # Tweety is eating (from parent)
print(bird.sound())  # Tweety says Chirp! (overridden)
print(bird.fly())    # Tweety is flying (specific to Bird)

# Checking the relationship
print("\n=== RELATIONSHIP ===")
print(f"Is Dog an Animal? {issubclass(Dog, Animal)}")    # True
print(f"Is Cat an Animal? {issubclass(Cat, Animal)}")    # True
print(f"Is Bird an Animal? {issubclass(Bird, Animal)}")  # True
print(f"Is Dog a Cat? {issubclass(Dog, Cat)}")          # False

One parent, many children key points:

  • One parent — a single base class at the top
  • Many children — multiple classes that inherit from the same parent
  • Shared features — all children get the parent's methods and attributes
  • Unique features — each child can add its own methods
  • Independent children — each child stands on its own

Quick Check: How many parent classes are there in hierarchical inheritance? (Answer: One parent class, with many child classes)

How Hierarchical Inheritance Works

2

Understanding the Mechanism

When you use hierarchical inheritance, each child class gets a copy of the parent's methods and attributes. Each child can use the parent's methods as they are, or they can override them to change the behavior. This is called method overriding.

The children are completely independent of each other. Changes made to one child don't affect the other children. They all share the common code from the parent, but each child can go its own way.

# How hierarchical inheritance works

class Vehicle:
    """Parent class - common vehicle features"""
    
    def __init__(self, brand, color):
        self.brand = brand
        self.color = color
        self.speed = 0
    
    def start(self):
        self.speed = 10
        return f"{self.brand} is starting. Speed: {self.speed} km/h"
    
    def stop(self):
        self.speed = 0
        return f"{self.brand} stopped"
    
    def accelerate(self):
        self.speed += 10
        return f"{self.brand} speeding up. Speed: {self.speed} km/h"
    
    def honk(self):
        return f"{self.brand} honks!"

# Child class 1 - Car
class Car(Vehicle):
    """Car is a vehicle"""
    
    def __init__(self, brand, color, doors=4):
        super().__init__(brand, color)  # Call parent constructor
        self.doors = doors
    
    # Override the honk method
    def honk(self):
        return f"{self.brand} car says Beep Beep!"
    
    # Car-specific method
    def open_trunk(self):
        return f"{self.brand} trunk is open"

# Child class 2 - Bike
class Bike(Vehicle):
    """Bike is a vehicle"""
    
    def __init__(self, brand, color, has_basket=False):
        super().__init__(brand, color)
        self.has_basket = has_basket
    
    # Override the honk method differently
    def honk(self):
        return f"{self.brand} bike says Ring Ring!"
    
    # Bike-specific method
    def pedal(self):
        return f"Pedaling the {self.brand} bike"

# Child class 3 - Truck
class Truck(Vehicle):
    """Truck is a vehicle"""
    
    def __init__(self, brand, color, load_capacity=1000):
        super().__init__(brand, color)
        self.load_capacity = load_capacity
    
    # Override the honk method differently
    def honk(self):
        return f"{self.brand} truck says HOOONK!"
    
    # Truck-specific method
    def load_cargo(self, weight):
        if weight <= self.load_capacity:
            return f"Loading {weight}kg cargo into {self.brand} truck"
        else:
            return f"Too heavy! {self.brand} can only carry {self.load_capacity}kg"

# Testing
print("=== CAR ===")
car = Car("Toyota", "Red", 4)
print(car.start())    # Parent method
print(car.honk())     # Overridden
print(car.open_trunk())  # Car-specific

print("\n=== BIKE ===")
bike = Bike("Hero", "Blue", True)
print(bike.start())   # Parent method
print(bike.honk())    # Overridden
print(bike.pedal())   # Bike-specific

print("\n=== TRUCK ===")
truck = Truck("Volvo", "White", 2000)
print(truck.start())  # Parent method
print(truck.honk())   # Overridden
print(truck.load_cargo(1500))  # Truck-specific

print("\n=== ALL CHILDREN ARE INDEPENDENT ===")
print(f"Car has {car.doors} doors")
print(f"Bike has basket? {bike.has_basket}")
print(f"Truck can carry {truck.load_capacity}kg")

How hierarchical inheritance works:

  • Children inherit — all child classes get parent methods
  • Method overriding — children can change parent methods
  • Independent children — changes in one child don't affect others
  • Child-specific features — each child can add its own methods
  • Shared code — common code is in the parent class only

Quick Check: When you change a method in one child class, does it affect other child classes? (Answer: No, each child is independent)

Sharing Common Features

3

Reusing Code with the Parent Class

The biggest advantage of hierarchical inheritance is code reuse. Instead of writing the same code in every child class, you write it once in the parent class, and all children get it automatically.

This saves you time and makes your code cleaner. If you need to change something that's common to all children, you only change it in one place — the parent class.

# Sharing common features in hierarchical inheritance

class Employee:
    """Parent class - common employee features"""
    
    def __init__(self, emp_id, name, salary):
        self.emp_id = emp_id
        self.name = name
        self.salary = salary
        self.attendance = []
    
    def mark_attendance(self, date):
        self.attendance.append(date)
        return f"{self.name} marked attendance for {date}"
    
    def get_salary(self):
        return f"{self.name}'s monthly salary: ${self.salary}"
    
    def work(self):
        return f"{self.name} is working"
    
    def take_break(self, minutes):
        return f"{self.name} took a {minutes} minute break"

# Child class 1 - Developer
class Developer(Employee):
    """Developer is an employee"""
    
    def __init__(self, emp_id, name, salary, programming_language):
        super().__init__(emp_id, name, salary)
        self.programming_language = programming_language
        self.code_written = 0
    
    # Override work method
    def work(self):
        self.code_written += 100
        return f"{self.name} is coding in {self.programming_language}"
    
    # Developer-specific method
    def debug_code(self):
        return f"{self.name} is debugging code"

# Child class 2 - Manager
class Manager(Employee):
    """Manager is an employee"""
    
    def __init__(self, emp_id, name, salary, team_size=0):
        super().__init__(emp_id, name, salary)
        self.team_size = team_size
        self.meetings = 0
    
    # Override work method
    def work(self):
        self.meetings += 1
        return f"{self.name} is leading a team of {self.team_size} people"
    
    # Manager-specific method
    def conduct_meeting(self, topic):
        self.meetings += 1
        return f"{self.name} is conducting a meeting about {topic}"

# Child class 3 - Designer
class Designer(Employee):
    """Designer is an employee"""
    
    def __init__(self, emp_id, name, salary, design_tool):
        super().__init__(emp_id, name, salary)
        self.design_tool = design_tool
        self.designs_completed = 0
    
    # Override work method
    def work(self):
        self.designs_completed += 1
        return f"{self.name} is designing with {self.design_tool}"
    
    # Designer-specific method
    def create_prototype(self):
        self.designs_completed += 1
        return f"{self.name} created a new prototype"

# Using the shared features
print("=== DEVELOPER ===")
dev = Developer("D001", "Alice", 80000, "Python")
print(dev.work())          # Overridden
print(dev.get_salary())    # From parent
print(dev.mark_attendance("2026-08-09"))  # From parent
print(dev.debug_code())    # Developer-specific

print("\n=== MANAGER ===")
mgr = Manager("M001", "Bob", 120000, 5)
print(mgr.work())          # Overridden
print(mgr.get_salary())    # From parent
print(mgr.mark_attendance("2026-08-09"))  # From parent
print(mgr.conduct_meeting("Project Review"))  # Manager-specific

print("\n=== DESIGNER ===")
des = Designer("D002", "Carol", 75000, "Figma")
print(des.work())          # Overridden
print(des.get_salary())    # From parent
print(des.mark_attendance("2026-08-09"))  # From parent
print(des.create_prototype())  # Designer-specific

print("\n=== SHARED FEATURES ===")
print(f"All employees have: emp_id, name, salary, attendance")
print(f"All employees can: work, get_salary, mark_attendance, take_break")

Sharing features key points:

  • Write once, use many times — common code in the parent
  • Code reuse — all children inherit parent methods
  • Easy maintenance — change the parent to update all children
  • Less duplication — don't repeat the same code
  • Consistent behavior — all children share the same base functionality

Quick Check: What is the main benefit of putting common code in the parent class? (Answer: Code reuse — write once, use in all children)

Each Child Has Its Own Identity

4

Adding Unique Features to Each Child

While all children share the parent's features, each child can also have its own unique methods and attributes. This is what makes hierarchical inheritance powerful — you get the best of both worlds: shared code and individual specialization.

# Each child has its own unique features

class Payment:
    """Parent class - common payment features"""
    
    def __init__(self, amount, currency="USD"):
        self.amount = amount
        self.currency = currency
        self.status = "pending"
    
    def process_payment(self):
        self.status = "processed"
        return f"Processing {self.currency} {self.amount}"
    
    def get_status(self):
        return f"Payment status: {self.status}"
    
    def refund(self):
        if self.status == "processed":
            self.status = "refunded"
            return f"Refunding {self.currency} {self.amount}"
        else:
            return "Cannot refund - payment not processed"

# Child class 1 - CreditCardPayment
class CreditCardPayment(Payment):
    """Credit card payment"""
    
    def __init__(self, amount, card_number, expiry_date, cvv):
        super().__init__(amount)
        self.card_number = card_number
        self.expiry_date = expiry_date
        self.cvv = cvv
    
    # Override process_payment
    def process_payment(self):
        # Validate card
        if len(self.card_number) == 16:
            self.status = "processed"
            return f"Credit card payment of ${self.amount} approved"
        else:
            self.status = "failed"
            return f"Invalid card number: {self.card_number}"
    
    # Unique method
    def save_card_for_future(self):
        return f"Card ending in {self.card_number[-4:]} saved for future"

# Child class 2 - PayPalPayment
class PayPalPayment(Payment):
    """PayPal payment"""
    
    def __init__(self, amount, email, password):
        super().__init__(amount)
        self.email = email
        self.password = password
    
    # Override process_payment
    def process_payment(self):
        if "@" in self.email:
            self.status = "processed"
            return f"PayPal payment of ${self.amount} from {self.email}"
        else:
            self.status = "failed"
            return f"Invalid email: {self.email}"
    
    # Unique method
    def get_paypal_balance(self):
        return f"Balance for {self.email}: $1,234.56"

# Child class 3 - BankTransferPayment
class BankTransferPayment(Payment):
    """Bank transfer payment"""
    
    def __init__(self, amount, account_number, routing_number):
        super().__init__(amount)
        self.account_number = account_number
        self.routing_number = routing_number
    
    # Override process_payment
    def process_payment(self):
        if len(self.routing_number) == 9:
            self.status = "processed"
            return f"Bank transfer of ${self.amount} from account {self.account_number[-4:]}"
        else:
            self.status = "failed"
            return f"Invalid routing number: {self.routing_number}"
    
    # Unique method
    def get_transaction_id(self):
        return f"Transaction ID: TXN{self.account_number[:6]}"

# Testing
print("=== CREDIT CARD PAYMENT ===")
credit = CreditCardPayment(100.00, "1234567812345678", "12/25", "123")
print(credit.process_payment())  # Overridden
print(credit.get_status())       # From parent
print(credit.save_card_for_future())  # Unique

print("\n=== PAYPAL PAYMENT ===")
paypal = PayPalPayment(75.50, "user@email.com", "pass123")
print(paypal.process_payment())  # Overridden
print(paypal.get_status())       # From parent
print(paypal.get_paypal_balance())  # Unique

print("\n=== BANK TRANSFER ===")
bank = BankTransferPayment(500.00, "987654321", "123456789")
print(bank.process_payment())    # Overridden
print(bank.get_status())         # From parent
print(bank.get_transaction_id()) # Unique

print("\n=== EACH CHILD IS UNIQUE ===")
print("All children share: amount, currency, status, process_payment(), refund()")
print("But each has its own unique methods and attributes")

Each child is unique key points:

  • Unique methods — each child can have its own methods
  • Unique attributes — each child can have its own properties
  • Method overriding — children can change how parent methods work
  • Independent — each child can work differently
  • Specialization — make each child good at its own thing

Quick Check: Can each child class have its own methods that other children don't have? (Answer: Yes, each child can have unique methods)

Working with Constructors

5

Initializing Parent and Child Classes

When you create an object from a child class, the child's __init__ method is called first. To properly set up the parent's attributes, you need to call the parent's __init__ method using super().__init__().

This ensures that all attributes from the parent are properly initialized before you add the child's own attributes.

# Working with constructors in hierarchical inheritance

class Product:
    """Parent class - common product features"""
    
    def __init__(self, product_id, name, price):
        print(f"Product __init__ called for {name}")
        self.product_id = product_id
        self.name = name
        self.price = price
        self.in_stock = True
    
    def display_info(self):
        return f"ID: {self.product_id}, Name: {self.name}, Price: ${self.price}"

# Child class 1 - Electronics
class Electronics(Product):
    """Electronic product"""
    
    def __init__(self, product_id, name, price, brand, warranty_years):
        print(f"Electronics __init__ called for {name}")
        super().__init__(product_id, name, price)  # Call parent constructor
        self.brand = brand
        self.warranty_years = warranty_years
    
    # Child-specific method
    def get_warranty_info(self):
        return f"{self.name} has {self.warranty_years} years warranty"

# Child class 2 - Clothing
class Clothing(Product):
    """Clothing product"""
    
    def __init__(self, product_id, name, price, size, material):
        print(f"Clothing __init__ called for {name}")
        super().__init__(product_id, name, price)  # Call parent constructor
        self.size = size
        self.material = material
    
    # Child-specific method
    def get_size_guide(self):
        return f"{self.name} size {self.size}, made of {self.material}"

# Child class 3 - Book
class Book(Product):
    """Book product"""
    
    def __init__(self, product_id, name, price, author, pages):
        print(f"Book __init__ called for {name}")
        super().__init__(product_id, name, price)  # Call parent constructor
        self.author = author
        self.pages = pages
    
    # Child-specific method
    def get_author_info(self):
        return f"Author: {self.author}, Pages: {self.pages}"

# Creating objects
print("=== ELECTRONICS ===")
laptop = Electronics("E001", "Laptop", 999.99, "Dell", 2)
print(laptop.display_info())
print(laptop.get_warranty_info())

print("\n=== CLOTHING ===")
shirt = Clothing("C001", "T-Shirt", 19.99, "L", "Cotton")
print(shirt.display_info())
print(shirt.get_size_guide())

print("\n=== BOOK ===")
book = Book("B001", "Python Guide", 49.99, "John Smith", 350)
print(book.display_info())
print(book.get_author_info())

# Note: If you forget to call super().__init__()
class BrokenProduct(Product):
    def __init__(self, product_id, name, price):
        # super().__init__(product_id, name, price)  # This line is missing
        self.discount = 10

# This would cause an error:
# broken = BrokenProduct("B001", "Broken", 100)
# print(broken.name)  # AttributeError!

print("\n=== CONSTRUCTOR CHAIN ===")
print("When creating a child object, the constructors run in this order:")
print("1. Child __init__")
print("2. Parent __init__ (via super())")

Constructors key points:

  • Call super() — always call super().__init__() in child classes
  • Initialize all attributes — both parent and child attributes
  • Order matters — parent is initialized before child
  • Don't forget — forgetting super() causes errors
  • Each child can have different parameters — children can have unique arguments

Quick Check: What happens if you don't call super().__init__() in the child class? (Answer: Parent attributes won't be initialized, causing AttributeError)

Real-World Examples

6

Seeing Hierarchical Inheritance in Action

# Real-world example: A School Management System

class Person:
    """Parent class - common person features"""
    
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address
        print(f"Creating person: {name}")
    
    def get_details(self):
        return f"Name: {self.name}, Age: {self.age}, Address: {self.address}"
    
    def celebrate_birthday(self):
        self.age += 1
        return f"{self.name} is now {self.age} years old"

# Child class 1 - Student
class Student(Person):
    """Student is a person"""
    
    def __init__(self, name, age, address, student_id, grade, subjects):
        super().__init__(name, age, address)
        self.student_id = student_id
        self.grade = grade
        self.subjects = subjects
        self.grades = {}
        print(f"Student created: {name} (ID: {student_id})")
    
    def study(self, subject):
        return f"{self.name} is studying {subject}"
    
    def add_grade(self, subject, score):
        self.grades[subject] = score
        return f"{self.name} got {score} in {subject}"
    
    def get_average(self):
        if self.grades:
            avg = sum(self.grades.values()) / len(self.grades)
            return f"{self.name}'s average score: {avg:.1f}"
        return f"{self.name} has no grades yet"

# Child class 2 - Teacher
class Teacher(Person):
    """Teacher is a person"""
    
    def __init__(self, name, age, address, teacher_id, subject, salary):
        super().__init__(name, age, address)
        self.teacher_id = teacher_id
        self.subject = subject
        self.salary = salary
        self.students = []
        print(f"Teacher created: {name} (ID: {teacher_id})")
    
    def teach(self, topic):
        return f"{self.name} is teaching {topic}"
    
    def add_student(self, student):
        self.students.append(student)
        return f"{student.name} added to {self.name}'s class"
    
    def get_student_count(self):
        return f"{self.name} has {len(self.students)} students"

# Child class 3 - Staff
class Staff(Person):
    """Staff is a person"""
    
    def __init__(self, name, age, address, staff_id, department, role):
        super().__init__(name, age, address)
        self.staff_id = staff_id
        self.department = department
        self.role = role
        print(f"Staff created: {name} (ID: {staff_id})")
    
    def work(self, task):
        return f"{self.name} is working on: {task}"
    
    def get_work_hours(self):
        return f"{self.name} works 40 hours per week"

# Using the system
print("=" * 50)
print("SCHOOL MANAGEMENT SYSTEM")
print("=" * 50)

print("\n=== CREATING STUDENT ===")
student = Student("Alice", 12, "123 School St", "S001", 7, ["Math", "Science"])
print(student.get_details())
print(student.celebrate_birthday())
print(student.study("Math"))
print(student.add_grade("Math", 95))
print(student.add_grade("Science", 88))
print(student.get_average())

print("\n=== CREATING TEACHER ===")
teacher = Teacher("Mr. Smith", 35, "456 Teacher Ave", "T001", "Math", 45000)
print(teacher.get_details())
print(teacher.teach("Algebra"))
print(teacher.add_student(student))
print(teacher.get_student_count())

print("\n=== CREATING STAFF ===")
staff = Staff("Ms. Johnson", 28, "789 Staff Blvd", "ST001", "Administration", "Secretary")
print(staff.get_details())
print(staff.work("Filing documents"))
print(staff.get_work_hours())

print("\n=== INHERITANCE CHAIN ===")
for cls in Student.__mro__:
    print(f"  {cls.__name__}")
print("\nStudent → Person → object")
print("Teacher → Person → object")
print("Staff → Person → object")

Real-world example key points:

  • Person — base class with common features (name, age, address)
  • Student — adds student-specific features (grade, subjects, grades)
  • Teacher — adds teacher-specific features (subject, salary, students)
  • Staff — adds staff-specific features (department, role)
  • All share — get_details(), celebrate_birthday() from Person

Quick Check: How many child classes does the Person class have in this example? (Answer: Three — Student, Teacher, and Staff)

Best Practices for Hierarchical Inheritance

7

Using Hierarchical Inheritance Effectively

# Best practices for hierarchical inheritance

# 1. Keep the parent class simple and focused
#  Good: Parent has only common features
class Animal:
    def __init__(self, name):
        self.name = name
    
    def eat(self):
        return f"{self.name} eats"

class Dog(Animal):
    def bark(self):
        return "Woof!"

class Cat(Animal):
    def meow(self):
        return "Meow!"

#  Bad: Parent has too much specialized code
class Animal:
    def bark(self):  # Not all animals bark!
        return "Bark"
    
    def meow(self):  # Not all animals meow!
        return "Meow"
    
    def fly(self):   # Not all animals fly!
        return "Fly"

# 2. Use meaningful names
#  Good
class Vehicle:
    pass

class Car(Vehicle):
    pass

class Bike(Vehicle):
    pass

#  Bad
class A:
    pass

class B(A):
    pass

class C(A):
    pass

# 3. Don't duplicate code across children
#  Good: Common code in parent
class Shape:
    def __init__(self, color):
        self.color = color

class Circle(Shape):
    pass

class Square(Shape):
    pass

#  Bad: Duplicate code in each child
class Circle:
    def __init__(self, color):
        self.color = color

class Square:
    def __init__(self, color):
        self.color = color

# 4. Use method overriding wisely
class Bird:
    def fly(self):
        return "Flying"

class Penguin(Bird):
    def fly(self):  # Penguins can't fly
        return "Penguins can't fly"

# 5. Keep the hierarchy logical
#  Good: Logical relationship
class Animal: pass
class Mammal(Animal): pass
class Dog(Mammal): pass

#  Bad: Illogical relationship
class Car: pass
class Dog(Car): pass  # A dog is not a car!

# 6. Use composition when inheritance doesn't fit
#  If the relationship is "has-a" not "is-a"
class Engine:
    def start(self):
        return "Engine started"

class Car:
    def __init__(self):
        self.engine = Engine()  # Car has an engine

# 7. Document your classes
class Product:
    """
    Base class for all products.
    Subclasses: Electronics, Clothing, Books
    """
    pass

Best practices summary:

  • Keep parent simple — only common, shared features in the parent
  • Use meaningful names — make it clear what each class does
  • Avoid duplication — don't repeat code across children
  • Override wisely — only override when you need to change behavior
  • Logical hierarchy — make sure the "is-a" relationship makes sense
  • Consider composition — if "has-a" fits better, use composition
  • Document — explain what each class is for

Quick Check: What should you do if you have the same code in multiple child classes? (Answer: Move the common code to the parent class)

Try It Yourself

Experiment with hierarchical inheritance in the editor below.

Loading Pyodide... 0%
Python Code Editor
========================================
HIERARCHICAL INHERITANCE PRACTICE
========================================

1. CREATING A PARENT CLASS
Animal created: Buddy

2. CREATING CHILD CLASSES
Animal created: Whiskers
Animal created: Bessie

3. USING THE CLASSES
Buddy says Woof!
Whiskers says Meow!
Bessie says Moo!

4. UNIQUE METHODS
Buddy is fetching
Whiskers is purring
Bessie is giving milk

5. CHECKING INHERITANCE
Is Dog an Animal? True
Is Cat an Animal? True
Is Cow an Animal? True

Hierarchical inheritance practice complete!
🏆

You've Got It!

You now understand hierarchical inheritance in Python. You know how one parent class can have many children, how to share code through the parent, and how to make each child unique.

Quick Quiz

Test what you've learned:

1. What is hierarchical inheritance?
2. In hierarchical inheritance, how many parent classes does each child have?
3. What is the main benefit of hierarchical inheritance?
4. What method should you call in a child class to initialize the parent class?
5. If you change a method in the parent class, what happens to the child classes?

Frequently Asked Questions

What is the difference between hierarchical and multilevel inheritance? ▼

Hierarchical inheritance has one parent with many children (one-to-many). Multilevel inheritance has a chain where each class inherits from the one above it (Grandparent → Parent → Child). In hierarchical, the children are siblings. In multilevel, they're in a straight line.

How many child classes can a parent have in hierarchical inheritance? ▼

There's no limit — a parent class can have as many child classes as you need. You can have 2, 3, 10, or even 100 child classes inheriting from the same parent. The key is that each child is independent and can have its own unique features.

Can child classes in hierarchical inheritance have their own children? ▼

Yes! A child class can also be a parent to other classes. This would create a more complex structure that combines hierarchical and multilevel inheritance. For example, Animal → Dog → Puppy (Dog is a child of Animal but also a parent of Puppy).

Do all child classes need to have the same attributes? ▼

No, each child class can have its own unique attributes. They all inherit the parent's attributes, but each child can add its own. For example, Dog might have a breed attribute, Cat might have a fur_color attribute, and Bird might have wing_span attribute — all different.

What's a common interview question about hierarchical inheritance? ▼

Common questions include: "Explain hierarchical inheritance with an example," "What's the difference between hierarchical and multiple inheritance?" and "Why would you use hierarchical inheritance instead of putting all features in one class?"

When should I use hierarchical inheritance? ▼

Use hierarchical inheritance when you have a clear "is-a" relationship and multiple types that share common features. For example, if you have a Vehicle class and multiple types of vehicles (Car, Bike, Truck, Bus) — all are vehicles, but each has different features and behaviors.

Where to Go From Here

Now that you understand hierarchical inheritance, check out these related topics:

Hybrid Inheritance

Learn about combining multiple types of inheritance.

Learn More →

Method Overriding

Learn more about overriding methods in child classes.

Learn More →

Abstraction

Learn about hiding complex implementation details.

Learn More →
Interview Resources
  • Python Syntax & Variables Interview Questions
  • Top SQL Interview Questions & Answers
  • SQL Joins: Displaying Data from Multiple Tables FAQ
  • Python Lists and Dictionaries Interview Questions
  • Python OOP Interview Questions
  • SQL Set Operators Interview Questions
Previous: Multilevel Inheritance Next: Hybrid Inheritance →