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: Multilevel Inheritance

Python Multilevel Inheritance - Complete Guide

Learn how classes inherit in a chain — from grandparent to parent to child.

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 Multilevel Inheritance?
  • The Inheritance Chain
  • Grandparent, Parent, and Child
  • Method Lookup in Multilevel Inheritance
  • super() in Multilevel Inheritance
  • Constructors in the Chain
  • 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 multilevel inheritance — a chain of inheritance
  • The inheritance chain — how classes are connected
  • Grandparent, parent, and child — the hierarchy
  • Method lookup — how Python finds methods
  • super() in the chain — calling ancestor methods
  • Constructors — initializing the whole chain

What is Multilevel Inheritance?

Multilevel inheritance is a type of inheritance where a class inherits from another class, which in turn inherits from another class. This creates a chain of inheritance, like a family tree where each generation passes down traits to the next.

Think of it like a family line: a grandparent passes traits to a parent, who passes traits to a child. Each generation adds its own unique characteristics while inheriting from the previous generation.

In Python, multilevel inheritance creates a hierarchy where each class inherits from the one above it. This allows you to build increasingly specialized classes while reusing code from the levels above.

💡 Key concept: Multilevel inheritance is a chain of inheritance where each class inherits from the class above it. It creates a hierarchy from general to specific.

The Inheritance Chain

1

Understanding the Chain

In multilevel inheritance, each class in the chain inherits from the class above it. This creates a linear hierarchy where each class builds on the previous ones.

# The inheritance chain

# Grandparent class (Level 1)
class Animal:
    """The base class for all animals"""
    
    def __init__(self, name):
        self.name = name
        print(f"Animal __init__ called for {name}")
    
    def eat(self):
        return f"{self.name} is eating"
    
    def sleep(self):
        return f"{self.name} is sleeping"

# Parent class (Level 2) - inherits from Animal
class Mammal(Animal):
    """A class representing mammals"""
    
    def __init__(self, name, fur_color):
        super().__init__(name)
        self.fur_color = fur_color
        print(f"Mammal __init__ called for {name}")
    
    def feed_milk(self):
        return f"{self.name} is feeding milk"
    
    def warm_blooded(self):
        return True

# Child class (Level 3) - inherits from Mammal
class Dog(Mammal):
    """A class representing dogs"""
    
    def __init__(self, name, fur_color, breed):
        super().__init__(name, fur_color)
        self.breed = breed
        print(f"Dog __init__ called for {name}")
    
    def bark(self):
        return f"{self.name} says Woof!"
    
    def fetch(self):
        return f"{self.name} is fetching"

# Grandchild class (Level 4) - inherits from Dog
class Puppy(Dog):
    """A class representing puppies"""
    
    def __init__(self, name, fur_color, breed, age):
        super().__init__(name, fur_color, breed)
        self.age = age
        print(f"Puppy __init__ called for {name}")
    
    def play(self):
        return f"{self.name} is playing"
    
    # Override the bark method
    def bark(self):
        return f"{self.name} says Yip Yip!"

# Creating a Puppy object
print("Creating a Puppy...")
puppy = Puppy("Max", "Golden", "Golden Retriever", 3)

# Methods from Animal (Level 1)
print(puppy.eat())    # Max is eating
print(puppy.sleep())  # Max is sleeping

# Methods from Mammal (Level 2)
print(puppy.feed_milk())  # Max is feeding milk
print(f"Warm blooded: {puppy.warm_blooded()}")  # True

# Methods from Dog (Level 3)
print(puppy.fetch())  # Max is fetching

# Methods from Puppy (Level 4)
print(puppy.play())   # Max is playing

# Overridden method
print(puppy.bark())   # Max says Yip Yip!

# The inheritance chain:
# Puppy → Dog → Mammal → Animal → object
print("Inheritance chain:")
for cls in Puppy.__mro__:
    print(f"  {cls.__name__}")
                                

The inheritance chain key points:

  • Linear chain — each class has exactly one parent
  • Levels — each level adds more specific functionality
  • All ancestors — child inherits from all classes above it
  • MRO — follows the chain from child up to object
  • Specialization — each level becomes more specific

Quick Check: What is the inheritance chain in multilevel inheritance? (Answer: A linear chain where each class inherits from the class above it)

Grandparent, Parent, and Child

2

The Three Generations of Inheritance

In multilevel inheritance, we often talk about three generations: grandparent, parent, and child. Each generation adds more specific functionality while inheriting from the generation above.

# Grandparent, Parent, and Child

# Grandparent class (most general)
class Vehicle:
    """A class representing a vehicle"""
    
    def __init__(self, brand, year):
        self.brand = brand
        self.year = year
        self.is_moving = False
    
    def start(self):
        self.is_moving = True
        return f"{self.brand} vehicle started"
    
    def stop(self):
        self.is_moving = False
        return f"{self.brand} vehicle stopped"
    
    def get_info(self):
        return f"{self.year} {self.brand} vehicle"

# Parent class (more specific)
class Car(Vehicle):
    """A class representing a car"""
    
    def __init__(self, brand, year, model, doors=4):
        super().__init__(brand, year)
        self.model = model
        self.doors = doors
        self.gps_enabled = False
    
    def enable_gps(self):
        self.gps_enabled = True
        return f"GPS enabled for {self.brand} {self.model}"
    
    def get_info(self):
        return f"{self.year} {self.brand} {self.model} with {self.doors} doors"

# Child class (most specific)
class SportsCar(Car):
    """A class representing a sports car"""
    
    def __init__(self, brand, year, model, doors=2, horsepower=400):
        super().__init__(brand, year, model, doors)
        self.horsepower = horsepower
        self.top_speed = 180
    
    def accelerate(self):
        return f"{self.brand} {self.model} is accelerating to {self.top_speed} mph"
    
    def get_info(self):
        return f"{super().get_info()} and {self.horsepower} HP"

# Creating objects
print("=== Vehicle (Grandparent) ===")
vehicle = Vehicle("Generic", 2020)
print(vehicle.get_info())  # 2020 Generic vehicle

print("\n=== Car (Parent) ===")
car = Car("Toyota", 2022, "Camry", 4)
print(car.get_info())  # 2022 Toyota Camry with 4 doors
print(car.enable_gps())  # GPS enabled for Toyota Camry

print("\n=== SportsCar (Child) ===")
sports_car = SportsCar("Ferrari", 2023, "F8", 2, 710)
print(sports_car.get_info())  # 2023 Ferrari F8 with 2 doors and 710 HP
print(sports_car.accelerate())  # Ferrari F8 is accelerating to 180 mph

# Checking the hierarchy
print(f"Is SportsCar a Car? {issubclass(SportsCar, Car)}")  # True
print(f"Is SportsCar a Vehicle? {issubclass(SportsCar, Vehicle)}")  # True
print(f"Is SportsCar an object? {issubclass(SportsCar, object)}")  # True
                                

Three generations key points:

  • Grandparent — most general, common functionality
  • Parent — more specific, extends grandparent
  • Child — most specific, extends parent
  • Each level — adds its own unique attributes and methods
  • Inheritance flows down — child has access to all methods from above

Quick Check: What are the three generations in multilevel inheritance? (Answer: Grandparent, parent, and child)

Method Lookup in Multilevel Inheritance

3

How Python Finds Methods in the Chain

When a method is called on an object in multilevel inheritance, Python searches for the method starting from the child class and moving up the chain. The first method found is the one that's used. This is the Method Resolution Order (MRO).

# Method lookup in multilevel inheritance

class A:
    def method(self):
        return "A's method"
    
    def common(self):
        return "A's common method"

class B(A):
    def method(self):
        return "B's method"

class C(B):
    def method(self):
        return "C's method"

class D(C):
    # No method defined here
    pass

# Creating objects
d = D()

# Method lookup order:
# 1. Check D (doesn't have method)
# 2. Check C (has method)
print(d.method())  # C's method

# For common method:
# 1. Check D (doesn't have common)
# 2. Check C (doesn't have common)
# 3. Check B (doesn't have common)
# 4. Check A (has common)
print(d.common())  # A's common method

# Method lookup chain
print("Method lookup chain:")
for cls in D.__mro__:
    print(f"  {cls.__name__}")
# D → C → B → A → object

# Another example with method overriding
class Grandparent:
    def message(self):
        return "Message from Grandparent"

class Parent(Grandparent):
    def message(self):
        return "Message from Parent"

class Child(Parent):
    def message(self):
        return "Message from Child"

class Grandchild(Child):
    pass

grandchild = Grandchild()
print(grandchild.message())  # Message from Child

# To call a specific version:
class SpecificChild(Child):
    def all_messages(self):
        return [
            self.message(),  # Child's version
            super().message(),  # Parent's version
            super(Parent, self).message()  # Grandparent's version
        ]

specific = SpecificChild()
print(specific.all_messages())
# ['Message from Child', 'Message from Parent', 'Message from Grandparent']
                                

Method lookup key points:

  • Starts at child — Python looks for the method in the child class first
  • Moves up the chain — if not found, moves to parent, then grandparent
  • First match wins — the first method found is used
  • MRO defines order — Method Resolution Order determines the search path
  • Can access ancestors — use super() to call specific versions

Quick Check: Where does Python first look for a method in multilevel inheritance? (Answer: In the child class)

super() in Multilevel Inheritance

4

Calling Ancestor Methods

In multilevel inheritance, super() follows the chain upward. It calls the next method in the MRO, allowing you to extend the behavior of ancestor classes.

# super() in multilevel inheritance

class Grandparent:
    def __init__(self, name):
        self.name = name
        print(f"Grandparent __init__: {name}")
    
    def work(self):
        return f"{self.name} works"

class Parent(Grandparent):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age
        print(f"Parent __init__: {name}, {age}")
    
    def work(self):
        return f"{self.name} works and earns money"

class Child(Parent):
    def __init__(self, name, age, school):
        super().__init__(name, age)
        self.school = school
        print(f"Child __init__: {name}, {age}, {school}")
    
    def work(self):
        return f"{self.name} studies at {self.school}"

class Grandchild(Child):
    def __init__(self, name, age, school, hobby):
        super().__init__(name, age, school)
        self.hobby = hobby
        print(f"Grandchild __init__: {name}, {age}, {school}, {hobby}")
    
    def work(self):
        parent_work = super().work()
        return f"{parent_work} and plays {self.hobby}"

# Creating a Grandchild
print("Creating Grandchild...")
grandchild = Grandchild("Alice", 10, "Python School", "coding")
print("\nWork:", grandchild.work())
# Alice studies at Python School and plays coding

# How super() works in the chain:
print("\nMethod chain with super():")
# Grandchild.work() calls:
# 1. super().work() → Child.work()
# 2. Child.work() → super().work() → Parent.work()
# 3. Parent.work() → super().work() → Grandparent.work()
# 4. Grandparent.work() returns

# The order of calls:
print("\nConstructor calls with super():")
# Grandchild.__init__ → Child.__init__ → Parent.__init__ → Grandparent.__init__

# Using super() to call specific ancestor methods
class Demo(Grandchild):
    def show_all_work(self):
        print("Direct call (self):", self.work())
        print("super() call:", super().work())
        print("super(Parent) call:", super(Parent, self).work())
        print("super(Grandparent) call:", super(Grandparent, self).work())

demo = Demo("Bob", 12, "Math School", "chess")
print("\nAll work versions:")
demo.show_all_work()
                                

super() in multilevel inheritance key points:

  • Follows the chain — super() moves up the inheritance chain
  • Calls next ancestor — calls the method in the next class in MRO
  • Chain of calls — each level calls super() to continue the chain
  • Can skip levels — super(Class, self) can call ancestors of a specific class
  • Essential for constructors — super().__init__() initializes all ancestors

Quick Check: In multilevel inheritance, what does super() call? (Answer: The method in the next class up the inheritance chain)

Constructors in the Chain

5

Initializing All Levels

In multilevel inheritance, each class should call its parent's constructor using super().__init__(). This ensures that all levels of the hierarchy are properly initialized.

# Constructors in multilevel inheritance

class Base:
    def __init__(self, value1):
        self.value1 = value1
        print(f"Base __init__: {value1}")

class Level1(Base):
    def __init__(self, value1, value2):
        super().__init__(value1)
        self.value2 = value2
        print(f"Level1 __init__: {value2}")

class Level2(Level1):
    def __init__(self, value1, value2, value3):
        super().__init__(value1, value2)
        self.value3 = value3
        print(f"Level2 __init__: {value3}")

class Level3(Level2):
    def __init__(self, value1, value2, value3, value4):
        super().__init__(value1, value2, value3)
        self.value4 = value4
        print(f"Level3 __init__: {value4}")

# Creating an object
print("Creating Level3 object...")
obj = Level3("A", "B", "C", "D")

# The constructor chain:
# Level3.__init__ → Level2.__init__ → Level1.__init__ → Base.__init__
print(f"\nobj.value1 = {obj.value1}")
print(f"obj.value2 = {obj.value2}")
print(f"obj.value3 = {obj.value3}")
print(f"obj.value4 = {obj.value4}")

# What happens if we forget super().__init__()?
class BrokenLevel(Level2):
    def __init__(self, value1, value2, value3, value4):
        # super().__init__(value1, value2, value3)  # Missing!
        self.value4 = value4

# This would cause issues because parent attributes aren't initialized
# Uncomment to see the error:
# broken = BrokenLevel("A", "B", "C", "D")
# print(broken.value1)  # AttributeError!

# Proper way: Always call super().__init__()
class GoodLevel(Level2):
    def __init__(self, value1, value2, value3, value4):
        super().__init__(value1, value2, value3)
        self.value4 = value4

good = GoodLevel("A", "B", "C", "D")
print(f"\nGoodLevel works: {good.value1}, {good.value2}, {good.value3}, {good.value4}")
                                

Constructors key points:

  • Call super().__init__() — always call the parent constructor
  • Chain of initialization — constructors are called from child up to grandparent
  • All attributes initialized — ensures all levels have their attributes set
  • Don't skip — forgetting to call super().__init__() causes errors
  • Order matters — parent attributes are initialized before child attributes

Quick Check: Why should you call super().__init__() in every child class? (Answer: To ensure all parent attributes are properly initialized)

Real-World Examples

6

Seeing Multilevel Inheritance in Action

# Real-world example: An Employee Management System

class Person:
    """Base class for all people"""
    
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address
        print(f"Person __init__: {name}")
    
    def introduce(self):
        return f"Hi, I'm {self.name}, {self.age} years old"
    
    def get_address(self):
        return f"{self.name} lives at {self.address}"

class Employee(Person):
    """A class representing an employee"""
    
    def __init__(self, name, age, address, employee_id, department):
        super().__init__(name, age, address)
        self.employee_id = employee_id
        self.department = department
        self.salary = 0
        print(f"Employee __init__: {name} ({employee_id})")
    
    def work(self):
        return f"{self.name} is working in {self.department}"
    
    def set_salary(self, amount):
        self.salary = amount
        return f"{self.name}'s salary set to ${amount}"

class Manager(Employee):
    """A class representing a manager"""
    
    def __init__(self, name, age, address, employee_id, department, team_size):
        super().__init__(name, age, address, employee_id, department)
        self.team_size = team_size
        self.team_members = []
        print(f"Manager __init__: {name} (team: {team_size})")
    
    def work(self):
        return f"{self.name} is managing a team of {self.team_size} people"
    
    def add_team_member(self, member):
        self.team_members.append(member)
        return f"{member} added to {self.name}'s team"

class Executive(Manager):
    """A class representing an executive"""
    
    def __init__(self, name, age, address, employee_id, department, team_size, executive_level):
        super().__init__(name, age, address, employee_id, department, team_size)
        self.executive_level = executive_level
        self.stock_options = 0
        print(f"Executive __init__: {name} (Level {executive_level})")
    
    def work(self):
        return f"{self.name} is leading the company as Level {self.executive_level} executive"
    
    def grant_stock_options(self, amount):
        self.stock_options = amount
        return f"{self.name} granted {amount} stock options"

# Using the system
print("=== Creating an Executive ===\n")
executive = Executive(
    name="Alice",
    age=45,
    address="123 Main St",
    employee_id="E001",
    department="Executive",
    team_size=10,
    executive_level="Senior"
)

print("\n=== Using Methods ===")
print(executive.introduce())  # Person method
print(executive.work())       # Executive method (overridden)
print(executive.set_salary(200000))  # Employee method
print(executive.add_team_member("Bob"))  # Manager method
print(executive.grant_stock_options(1000))  # Executive method

print("\n=== Inheritance Chain ===")
print("Executive → Manager → Employee → Person → object")
for cls in Executive.__mro__:
    print(f"  {cls.__name__}")
                                

Real-world example key points:

  • Person — base class with common attributes
  • Employee — adds work-related attributes
  • Manager — adds management capabilities
  • Executive — adds leadership and stock options
  • Method overriding — each level customizes the work() method

Quick Check: What does each level in the Employee hierarchy add? (Answer: Each level adds more specific attributes and methods)

Best Practices for Multilevel Inheritance

7

Using Multilevel Inheritance Effectively

# Best practices for multilevel inheritance

# 1. Keep the chain shallow (2-3 levels)
#  Good: 3 levels
class Animal: pass
class Mammal(Animal): pass
class Dog(Mammal): pass

#  Bad: Too many levels
class A: pass
class B(A): pass
class C(B): pass
class D(C): pass
class E(D): pass
class F(E): pass

# 2. Use logical progression
#  Good: Each level adds meaningful specialization
class Vehicle: pass
class Car(Vehicle): pass
class SportsCar(Car): pass

#  Bad: Adding unrelated features
class Animal: pass
class Mammal(Animal): pass
class FlyingMammal(Mammal): pass  # This might be better as a mixin

# 3. Always call super().__init__()
class Grandparent:
    def __init__(self, value):
        self.value = value

class Parent(Grandparent):
    def __init__(self, value, extra):
        super().__init__(value)  #  Good
        self.extra = extra

class Child(Parent):
    def __init__(self, value, extra, more):
        super().__init__(value, extra)  #  Good
        self.more = more

# 4. Use method overriding for specialization
class Shape:
    def area(self):
        return 0

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height

class Square(Rectangle):
    def __init__(self, side):
        super().__init__(side, side)
    
    # No need to override area - it works correctly

# 5. Document the inheritance chain
class Product:
    """
    Base class for products.
    
    Subclasses:
        ElectronicProduct: Products with electronics
        FoodProduct: Products that are food items
        BookProduct: Products that are books
    """
    pass

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

class Car:
    def __init__(self):
        self.engine = Engine()  # Composition, not inheritance

# 7. Avoid deep chains for simple cases
# For simple cases, inheritance might be overkill
class SimpleClass:
    pass
# Instead of creating a chain of 3 classes for simple functionality
                                

Best practices summary:

  • Keep chains shallow — avoid deep inheritance hierarchies
  • Logical progression — each level should add meaningful functionality
  • Call super().__init__() — always initialize parent classes
  • Override for specialization — use method overriding to customize behavior
  • Document the chain — explain the inheritance relationship
  • Prefer composition — when inheritance doesn't fit the relationship

Quick Check: How many levels should a multilevel inheritance chain have? (Answer: 2-3 levels maximum, keep it shallow)

Try It Yourself

Experiment with multilevel inheritance in the editor below.

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

1. BASIC MULTILEVEL INHERITANCE
Hello from Child

2. USING SUPER()
C.show() calls:
C
B
A

3. CONSTRUCTOR CHAIN
Z __init__
Y __init__
X __init__

4. CHECKING MRO
MRO for Z: ['Z', 'Y', 'X', 'object']

Multilevel inheritance practice complete!
🏆

You've Got It!

You now understand multilevel inheritance in Python. You know how classes inherit in a chain, how to use super(), and how to initialize all levels properly.

Quick Quiz

Test what you've learned:

1. What is multilevel inheritance?
2. In multilevel inheritance, which class is the most general?
3. What does super() do in multilevel inheritance?
4. Why should you call super().__init__() in every child class?
5. What is the recommended depth for multilevel inheritance?

Frequently Asked Questions

What is the difference between multilevel and multiple inheritance? ▼

Multilevel inheritance is a chain where each class inherits from one parent (Grandparent → Parent → Child). Multiple inheritance is where a class inherits from more than one parent (Child inherits from Parent1 and Parent2). Multilevel is a vertical chain; multiple is a horizontal combination.

Can I have more than three levels in multilevel inheritance? ▼

Yes, you can have any number of levels. However, it's recommended to keep the chain shallow (2-3 levels) to avoid complexity. Deep hierarchies become hard to understand and maintain.

What happens if I don't call super().__init__()? ▼

If you don't call super().__init__(), the parent class's attributes won't be initialized. This can lead to AttributeError when you try to access parent attributes. Always call super().__init__() in the child class's constructor.

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

Common questions include: "What is the difference between multilevel and multiple inheritance?" "Explain how method lookup works in multilevel inheritance" and "What is the purpose of super() in multilevel inheritance?"

When should I use multilevel inheritance? ▼

Use multilevel inheritance when you have a clear hierarchy where each level adds more specific functionality. For example, Animal → Mammal → Dog → Puppy. Each level adds more specific attributes and behaviors.

Can a child class access the grandparent's methods directly? ▼

Yes, a child class can access the grandparent's methods directly. Since the child inherits from the parent, and the parent inherits from the grandparent, the child has access to all methods in the chain. You can call grandparent methods just like any other method.

Where to Go From Here

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

Hierarchical Inheritance

Learn about multiple children from one parent.

Learn More →

Hybrid Inheritance

Learn about combining multiple and multilevel inheritance.

Learn More →

Method Overriding

Learn more about overriding methods in subclasses.

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: Multiple Inheritance Next: Hierarchical Inheritance →