Introduction
In Python, inheritance is like creating a family tree for your classes. It allows you to create new classes (child classes) that inherit properties and behaviors from existing classes (parent classes).
Understanding Classes as Blueprints
Think of a class as a blueprint for creating objects. It defines the attributes (properties) and methods (behaviors) that objects of that class will have.
Inheritance: Building Upon Existing Blueprints allows you to create a child class that inherits everything from its parent class, like a basic structure. The child class can then add its own unique attributes and methods, specializing the blueprint further.
Benefits of Inheritance
- Code Reusability: You don't have to rewrite common code in every class. The child class inherits the parent's functionality.
- Code Organization: It helps organize code logically, grouping related classes in a hierarchy.
- Extensibility: You can easily create new classes with specialized behaviors by extending existing ones.
Basic Syntax
Here's how you define inheritance in Python:
class ParentClass:
# Parent class attributes and methods
class ChildClass(ParentClass):
# Child class attributes and methodsExplanation:
- We define the
ParentClasswith its attributes and methods - We define the
ChildClassthat inherits fromParentClass - Now,
ChildClasshas access to all the attributes and methods ofParentClass - The
ChildClasscan define its own additional attributes and methods, specific to its needs
Types of Inheritance
In Python, based upon the number of child and parent classes involved, there are five types of inheritance:
- Single inheritance
- Multiple Inheritance
- Multilevel inheritance
- Hierarchical Inheritance
- Hybrid Inheritance
Single Inheritance
In single inheritance, a child class inherits from a single parent class.

Example
# Base class
class Vehicle:
def Vehicle_info(self):
print('Inside Vehicle class')
# Child class
class Car(Vehicle):
def car_info(self):
print('Inside Car class')
# Create object of Car
car = Car()
# access Vehicle's info using car object
car.Vehicle_info()
car.car_info()Output:
Inside Vehicle class
Inside Car classMultiple Inheritance
In multiple inheritance, one child class can inherit from multiple parent classes.

Example
# Parent class 1
class Person:
def person_info(self, name, age):
print('Inside Person class')
print('Name:', name, 'Age:', age)
# Parent class 2
class Company:
def company_info(self, company_name, location):
print('Inside Company class')
print('Name:', company_name, 'location:', location)
# Child class
class Employee(Person, Company):
def Employee_info(self, salary, skill):
print('Inside Employee class')
print('Salary:', salary, 'Skill:', skill)
# Create object of Employee
emp = Employee()
# access data
emp.person_info('Jessa', 28)
emp.company_info('Google', 'Atlanta')
emp.Employee_info(12000, 'Machine Learning')Output:
Inside Person class
Name: Jessa Age: 28
Inside Company class
Name: Google location: Atlanta
Inside Employee class
Salary: 12000 Skill: Machine LearningMultilevel Inheritance
In multilevel inheritance, a class inherits from a child class or derived class. This creates a chain of classes.

Example
# Base class
class Vehicle:
def Vehicle_info(self):
print('Inside Vehicle class')
# Child class
class Car(Vehicle):
def car_info(self):
print('Inside Car class')
# Child class
class SportsCar(Car):
def sports_car_info(self):
print('Inside SportsCar class')
# Create object of SportsCar
s_car = SportsCar()
# access Vehicle's and Car info using SportsCar object
s_car.Vehicle_info()
s_car.car_info()
s_car.sports_car_info()Output:
Inside Vehicle class
Inside Car class
Inside SportsCar classHierarchical Inheritance
In hierarchical inheritance, more than one child class is derived from a single parent class.

Example
class Vehicle:
def info(self):
print("This is Vehicle")
class Car(Vehicle):
def car_info(self, name):
print("Car name is:", name)
class Truck(Vehicle):
def truck_info(self, name):
print("Truck name is:", name)
obj1 = Car()
obj1.info()
obj1.car_info('BMW')
obj2 = Truck()
obj2.info()
obj2.truck_info('Ford')Output:
This is Vehicle
Car name is: BMW
This is Vehicle
Truck name is: FordHybrid Inheritance
When inheritance consists of multiple types or a combination of different inheritance patterns, it's called hybrid inheritance.

Example
class Vehicle:
def vehicle_info(self):
print("Inside Vehicle class")
class Car(Vehicle):
def car_info(self):
print("Inside Car class")
class Truck(Vehicle):
def truck_info(self):
print("Inside Truck class")
# Sports Car can inherits properties of Vehicle and Car
class SportsCar(Car, Vehicle):
def sports_car_info(self):
print("Inside SportsCar class")
# create object
s_car = SportsCar()
s_car.vehicle_info()
s_car.car_info()
s_car.sports_car_info()Note: In this example, both hierarchical and multiple inheritance exist. We have a parent class Vehicle with two child classes Car and Truck (hierarchical inheritance). Additionally, SportsCar inherits from both Car and Vehicle (multiple inheritance).
Python's super() Function
What is super()?
When a class inherits all properties and behavior from the parent class, we can refer to the parent class by using the super() function. The super function returns a temporary object of the parent class that allows us to call a parent class method inside a child class method.
Benefits of Using super()
- No Need to Remember Parent Class Names: We don't need to specify the parent class name to access its methods, making code maintenance easier.
- Works with All Inheritance Types: We can use
super()in both single and multiple inheritances. - Promotes Code Reusability: There's no need to write the entire function again.
- Handles Multiple Inheritance Gracefully: In multiple inheritance scenarios,
super()follows the Method Resolution Order (MRO). - Makes Code More Maintainable: If you change the parent class name, you don't need to update it everywhere.
Basic Syntax
super().method_name(arguments)In __init__ Constructor:
super().__init__(parent_parameters)Detailed Examples
Example 1: Basic Usage in Single Inheritance
Scenario: Using super() to call the parent class constructor
# Parent Class
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
print(f"Person constructor called for {name}")
def display_info(self):
return f"Name: {self.name}, Age: {self.age}"
# Child Class - Using super()
class Student(Person):
def __init__(self, name, age, student_id, gpa):
# Call parent constructor using super()
super().__init__(name, age)
# Add child-specific attributes
self.student_id = student_id
self.gpa = gpa
print(f"Student constructor called for {name}")
def display_student_info(self):
# Call parent method using super()
parent_info = super().display_info()
return f"{parent_info}, ID: {self.student_id}, GPA: {self.gpa}"
# Usage
student = Student("John Smith", 16, "S001", 3.7)
print(student.display_student_info())Output:
Person constructor called for John Smith
Student constructor called for John Smith
Name: John Smith, Age: 16, ID: S001, GPA: 3.7Explanation:
super().__init__(name, age)calls the parent classPerson's constructor- This initializes
nameandageattributes inherited fromPerson - Then the child class adds its own attributes (
student_id,gpa) super().display_info()calls the parent's method from within the child's method
Example 2: Without super() vs With super()
Without super() - Direct Parent Class Name:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
class iPhone(Product):
def __init__(self, name, price, model, storage):
# Direct parent class call - NOT RECOMMENDED
Product.__init__(self, name, price)
self.model = model
self.storage = storageWith super() - Recommended Approach:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
class iPhone(Product):
def __init__(self, name, price, model, storage):
# Using super() - RECOMMENDED
super().__init__(name, price)
self.model = model
self.storage = storageWhy super() is Better:
- If you rename
ProducttoAppleProduct, withsuper()you only change it once - Without
super(), you'd need to find and replaceProduct.__init__everywhere super()is more maintainable and less error-prone
Example 3: Using super() in Multilevel Inheritance
# Grandparent Class
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
print("Product initialized")
def display(self):
return f"Product: {self.name}, Price: ${self.price}"
# Parent Class
class AppleDevice(Product):
def __init__(self, name, price, os_version):
super().__init__(name, price) # Calls Product.__init__
self.os_version = os_version
print("AppleDevice initialized")
def display(self):
return f"{super().display()}, OS: {self.os_version}"
# Child Class
class iPhone(AppleDevice):
def __init__(self, name, price, os_version, model):
super().__init__(name, price, os_version) # Calls AppleDevice.__init__
self.model = model
print("iPhone initialized")
def display(self):
return f"{super().display()}, Model: {self.model}"
# Usage
iphone = iPhone("iPhone 15 Pro", 999, "iOS 17", "A3102")
print(iphone.display())Output:
Product initialized
AppleDevice initialized
iPhone initialized
Product: iPhone 15 Pro, Price: $999, OS: iOS 17, Model: A3102Example 4: Calling Parent Methods (Not Just __init__)
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def calculate_total(self, quantity):
return self.price * quantity
def display_price(self):
return f"${self.price}"
class DiscountedProduct(Product):
def __init__(self, name, price, discount_percent):
super().__init__(name, price)
self.discount_percent = discount_percent
# Override method but use parent's logic
def calculate_total(self, quantity):
# Get the original total from parent
original_total = super().calculate_total(quantity)
# Apply discount
discount = original_total * (self.discount_percent / 100)
return original_total - discount
def display_price(self):
# Use parent's display and add discount info
original = super().display_price()
discounted = self.price * (1 - self.discount_percent/100)
return f"{original} → ${discounted:.2f} ({self.discount_percent}% off)"
# Usage
product = DiscountedProduct("MacBook Air", 999, 10)
print(product.display_price())
print(f"Total for 2 units: ${product.calculate_total(2):.2f}")Output:
$999 → $899.10 (10% off)
Total for 2 units: $1798.20Common Patterns and Best Practices
Pattern 1: Always Call super().__init__() First
class Child(Parent):
def __init__(self, parent_params, child_params):
super().__init__(parent_params) # Initialize parent first
self.child_attribute = child_params # Then add child attributesPattern 2: Extend Parent Method Behavior
class Child(Parent):
def some_method(self):
# Do parent's work first
result = super().some_method()
# Add child-specific behavior
result += " and child's addition"
return resultPattern 3: Completely Override (No super() needed)
class Child(Parent):
def some_method(self):
# Completely new implementation, ignore parent's version
return "Child's own implementation"Method Resolution Order (MRO)
When using super() with multiple inheritance, Python uses MRO to determine which parent method to call:
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
super().show()
class C(A):
def show(self):
print("C")
super().show()
class D(B, C):
def show(self):
print("D")
super().show()
d = D()
d.show()
print(f"MRO: {[cls.__name__ for cls in D.__mro__]}")Output:
D
B
C
A
MRO: ['D', 'B', 'C', 'A', 'object']Common Mistakes to Avoid
Mistake 1: Forgetting self in parent call
# WRONG
super().__init__(name, age) # Correct - self is automatic with super()
Parent.__init__(name, age) # WRONG - missing self
# CORRECT
Parent.__init__(self, name, age) # If calling directlyMistake 2: Not calling parent constructor
class Child(Parent):
def __init__(self, child_param):
# WRONG - parent's __init__ never called
self.child_param = child_param
def __init__(self, parent_param, child_param):
# CORRECT
super().__init__(parent_param)
self.child_param = child_paramQuick Reference
Usage | Syntax | Purpose |
Call parent constructor | super().__init__(params) | Initialize parent class attributes |
Call parent method | super().method_name(params) | Use parent's method implementation |
Get parent class | super() | Returns temporary parent object |
Check MRO | ClassName.__mro__ | See method resolution order |
Understanding Python's issubclass() Function
What is issubclass()?
In Python, we can verify whether a particular class is a subclass of another class using the built-in issubclass() function. This function returns True if the given class is the subclass of the specified class, otherwise False.
Syntax
issubclass(class, classinfo)Parameters:
class: The class to be checked (the potential subclass)classinfo: A class, type, or a tuple of classes or data types to check against
Return Value:
- Returns
Trueifclassis a subclass ofclassinfo - Returns
Falseotherwise
Basic Example
class Company:
def fun1(self):
print("Inside parent class")
class Employee(Company):
def fun2(self):
print("Inside child class.")
class Player:
def fun3(self):
print("Inside Player class.")
# Check if Employee is a subclass of Company
print(issubclass(Employee, Company)) # True
# Check if Employee is a subclass of list
print(issubclass(Employee, list)) # False
# Check if Player is a subclass of Company
print(issubclass(Player, Company)) # False
# Check if Employee is a subclass of either list or Company
print(issubclass(Employee, (list, Company))) # True
# Check if Company is a subclass of either list or Company
print(issubclass(Company, (list, Company))) # True (a class is considered a subclass of itself)Output:
True
False
False
True
TrueDetailed Examples
Example 1: Single Inheritance Verification
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
class Student(Person):
def __init__(self, name, age, student_id):
Person.__init__(self, name, age)
self.student_id = student_id
class Teacher(Person):
def __init__(self, name, age, teacher_id):
Person.__init__(self, name, age)
self.teacher_id = teacher_id
class Staff:
def __init__(self, staff_id):
self.staff_id = staff_id
# Verification Tests
print("=== Single Inheritance Checks ===")
print(f"Is Student a subclass of Person? {issubclass(Student, Person)}")
print(f"Is Teacher a subclass of Person? {issubclass(Teacher, Person)}")
print(f"Is Student a subclass of Teacher? {issubclass(Student, Teacher)}")
print(f"Is Staff a subclass of Person? {issubclass(Staff, Person)}")
print(f"Is Person a subclass of Person? {issubclass(Person, Person)}") # A class is a subclass of itselfOutput:
=== Single Inheritance Checks ===
Is Student a subclass of Person? True
Is Teacher a subclass of Person? True
Is Student a subclass of Teacher? False
Is Staff a subclass of Person? False
Is Person a subclass of Person? TrueExample 2: Multilevel Inheritance Verification
class Person:
pass
class Teacher(Person):
pass
class DepartmentHead(Teacher):
pass
class Student(Person):
pass
print("=== Multilevel Inheritance Checks ===")
# Direct inheritance
print(f"Is DepartmentHead a subclass of Teacher? {issubclass(DepartmentHead, Teacher)}")
print(f"Is Teacher a subclass of Person? {issubclass(Teacher, Person)}")
# Indirect inheritance (through the chain)
print(f"Is DepartmentHead a subclass of Person? {issubclass(DepartmentHead, Person)}")
# Not in the same hierarchy
print(f"Is Student a subclass of Teacher? {issubclass(Student, Teacher)}")
print(f"Is DepartmentHead a subclass of Student? {issubclass(DepartmentHead, Student)}")Output:
=== Multilevel Inheritance Checks ===
Is DepartmentHead a subclass of Teacher? True
Is Teacher a subclass of Person? True
Is DepartmentHead a subclass of Person? True
Is Student a subclass of Teacher? False
Is DepartmentHead a subclass of Student? FalseKey Insight: issubclass() checks the entire inheritance chain, not just direct parent-child relationships.
Example 3: Checking Against Multiple Possible Parents
class Person:
pass
class Student(Person):
pass
class Teacher(Person):
pass
class Administrator(Person):
pass
class Visitor:
pass
# Define valid school member types
school_member_types = (Student, Teacher, Administrator)
print("=== Checking Against Multiple Parents ===")
# Check if classes are valid school members
print(f"Is Student a school member type? {issubclass(Student, school_member_types)}")
print(f"Is Teacher a school member type? {issubclass(Teacher, school_member_types)}")
print(f"Is Visitor a school member type? {issubclass(Visitor, school_member_types)}")
# Alternative: check against Person and other types
authorized_types = (Person, Visitor)
print(f"Is Student authorized? {issubclass(Student, authorized_types)}")
print(f"Is Visitor authorized? {issubclass(Visitor, authorized_types)}")Output:
=== Checking Against Multiple Parents ===
Is Student a school member type? True
Is Teacher a school member type? True
Is Visitor a school member type? False
Is Student authorized? True
Is Visitor authorized? TruePractical Use Cases
Type Validation in Functions
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
class iPhone(Product):
pass
class iPad(Product):
pass
class MacBook(Product):
pass
def apply_apple_discount(product_class):
"""Apply discount only to Apple product classes"""
apple_products = (iPhone, iPad, MacBook)
if issubclass(product_class, apple_products):
print(f"{product_class.__name__} is eligible for Apple discount!")
return True
else:
print(f"{product_class.__name__} is not an Apple product.")
return False
# Test discount function
print("=== Discount Validation ===")
apply_apple_discount(iPhone)
apply_apple_discount(MacBook)
apply_apple_discount(Product)Output:
=== Discount Validation ===
iPhone is eligible for Apple discount!
MacBook is eligible for Apple discount!
Product is not an Apple product.Important Notes
- A class is always a subclass of itself:
issubclass(Student, Student)returnsTrue - Works with entire hierarchy:
issubclass()checks the complete inheritance chain, not just direct parents - All classes inherit from
object: In Python 3,issubclass(AnyClass, object)always returnsTrue - First parameter must be a class: Passing an instance will raise a
TypeError
# WRONG - will raise TypeError
student_obj = Student("John", 20, "S001")
issubclass(student_obj, Person) # TypeError!
# CORRECT - use the class itself
issubclass(Student, Person) # True- Use tuple for OR logic:
issubclass(Child, (Parent1, Parent2))checks if Child inherits from Parent1 OR Parent2 - Returns
Falsefor unrelated classes: If there's no inheritance relationship, it returnsFalse
Comparison with isinstance()
Function | Checks | First Parameter | Second Parameter |
issubclass(A, B) | Class relationships | Must be a class | Class or tuple of classes |
isinstance(obj, A) | Object type | Can be an instance | Class or tuple of classes |
Quick Reference
Use Case | Syntax Example | Purpose |
Check direct inheritance | issubclass(Child, Parent) | Verify parent-child relationship |
Check inheritance chain | issubclass(Grandchild, Grandparent) | Verify multilevel inheritance |
Check multiple parents | issubclass(Child, (Parent1, Parent2)) | Verify if child inherits from any parent |
Check against built-ins | issubclass(CustomClass, list) | Verify inheritance from built-in types |
Self-check | issubclass(Class, Class) | Always returns True |
Validate class types | issubclass(cls, ValidTypes) | Input validation in functions |
# Basic usage examples
issubclass(ChildClass, ParentClass) # True if ChildClass inherits from ParentClass
issubclass(ChildClass, (Parent1, Parent2, Parent3)) # True if inherits from ANY
issubclass(MyClass, MyClass) # Always True
issubclass(Grandchild, Grandparent) # True if connected through inheritance
issubclass(CustomList, list) # True if CustomList inherits from list