Inheritance In Python

Inheritance In Python

13 Aug 2024
Beginner
672 Views
26 min read

Introduction to Inheritance in Python

Inheritance in Python allows us to "inherit" characteristics or features from previously written classes into newly created classes. Inheritance allows us to reuse code in the program by building a new class from an existing one rather than starting from scratch. It is one of the object-oriented programming concepts.

In this Python tutorial, we will go over inheritance in Python with appropriate examples. We will teach base classes, derived classes, method overriding, and the benefits and drawbacks of inheritance using examples. So, let us begin by examining "Understanding Inheritance in Python"

Understanding Inheritance in Python

  • In Python inheritance, the new class inherits from the older one. All of the functions and attributes of the older class are copied into the new class without altering the syntax. These new classes are referred to as derived classes, whereas the old ones are known as base classes.
  • For example, inheritance is frequently used in biology to represent the transmission of genetic features from parents to children. Similarly, we have parent classes (base) and child classes (derived classes). In inheritance, classes are derived from existing classes. The existing classes are the parent/base classes from which the child classes inherit their characteristics and methods.

What is Inheritance in Python?

  • In Python, inheritance is a mechanism that allows a new class, called a derived class, to inherit attributes and functions from an existing class, called a base class.
  • This enables the derived class to reuse code from the base class, increasing development efficiency and code reusability.
  • Inheritance also allows the derived class to expand or customize the functionality of the base class without changing the original code.

Benefits of Using Inheritance

Inheritance lets you transfer the properties of one class (the base class) to another, the derived class. The advantages of inheritance in Python are as follows.

  • It accurately reflects real-world relationships.
  • It allows for the reuse of code. We don't need to write the same code repeatedly. It also allows us to add new features to a class without altering it.
  • It is transitive in nature, which implies that if class B inherits from class A, all of B's subclasses will also inherit from class A.
  • Inheritance provides a basic and understandable model structure.
  • An inheritance reduces the cost of development and maintenance.

How to Implement Inheritance in Python

In Python, inheritance is achieved by creating a new class with an existing class as its parent. The syntax is simple, and the derived class inherits all of the characteristics and methods from the base class, allowing you to expand or modify them as needed.

Let us suppose a scenario in which we handle various types of employees in an organization.

  • Base Class: We begin with the base class Employee, which provides typical characteristics such as name and salary, as well as a function display_info() for printing employee information.
  • Derived Class: We then build a derived class Manager, which is inherited from the employee and adds a unique attribute, department, to handle manager-specific characteristics.

Example:

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

    def display_info(self):
        print(f"Name: {self.name}, Salary: {self.salary}")

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

    def display_info(self):
        super().display_info()
        print(f"Department: {self.department}")

# Example Usage
manager = Manager("Alice", 90000, "IT")
manager.display_info()

Output

Name: Alice, Salary: 90000
Department: IT

Explanation

Here, the employee class is the base class and has name and pay attributes, as well as a method to show this information. Class Manager inherits from class Employee, has an additional attribute called department, and in its display_info() method, it overrides the same method of Employee with extra information about the department.When an instance of Manager is created, and display_info() is invoked, it displays both the base class characteristics and the additional department information.

Types of Inheritance in Python with Examples

There are 5 different types of inheritance in Python. They are as follows:
  1. Single Inheritance
  2. Multiple Inheritance
  3. Multilevel Inheritance
  4. Hierarchical Inheritance
  5. Hybrid Inheritance

Let us use a "University" example to demonstrate all five types of inheritance:

1. Single Inheritance in Python

  • Single inheritance is the simplest type of inheritance, in which a single child class originated from a single parent class. Because of its open nature, it is also known as Single Inheritance.
  • Single inheritance allows a class to inherit characteristics and methods from only one base class. In our example, the Student class derives from the Person class, acquiring the ability to use display_name() and introducing its function study().

Example

# Base class
class Person:
    def __init__(self, name):
        self.name = name

    def display_name(self):
        print(f"Name: {self.name}")

# Derived class
class Student(Person):
    def study(self):
        print(f"{self.name} is studying")

# Example Usage
student = Student("Alice")
student.display_name()  # Inherited method
student.study()         # Derived class method

Output

Name: Alice
Alice is studying

Explanation

The Student class inherits the display_name() function from Person and also has its own study() method. The result displays inherited and derived functionalities.

2. Multiple Inheritance

  • Multiple inheritance is a mechanism of inheriting one child class from two or more parent classes. In other words, it will allow access to all methods and attributes of its parents from a child class.
  • Multiple inheritance is where a derived class is able to inherit from more than one base class. In our example, CourseStudent inherits from both Person and Course, merging their attributes into a single class.

Example

# Base classes
class Person:
    def __init__(self, name):
        self.name = name

class Course:
    def __init__(self, course_name):
        self.course_name = course_name

# Derived class
class CourseStudent(Person, Course):
    def __init__(self, name, course_name):
        Person.__init__(self, name)
        Course.__init__(self, course_name)

    def enroll(self):
        print(f"{self.name} has enrolled in {self.course_name}")

# Example Usage
student = CourseStudent("Bob", "Python Programming")
student.enroll()  # Method from CourseStudent

Output

Bob has enrolled in Python Programming

Explanation

This code defines two classes, Person and Course, each with its unique set of properties. The CourseStudent class inherits from both Person and Course, so it can access attributes from both parent classes. The enrollment method in CourseStudent publishes a message indicating that a student has registered for a given course. In "Python Programming," an instance of CourseStudent is created for "Bob," and the enroll method is used to display the enrollment message.

3. Multilevel Inheritance

  • Multilevel inheritance goes a step higher than the parent-child relationship. It allows children to have the concept of grandchildren, great-grandchildren, grandparents, and so forth.
  • Multilevel inheritance is a chain of classes where one class is inheriting from another derived class. In our case, the Student inherits from the Department, which then inherits from the University.

Example

# Base class
class University:
    def __init__(self, name):
        self.name = name

    def display_university(self):
        print(f"University: {self.name}")

# Derived class
class Department(University):
    def __init__(self, name, department_name):
        super().__init__(name)
        self.department_name = department_name

    def display_department(self):
        print(f"Department: {self.department_name}")

# Further derived class
class Student(Department):
    def __init__(self, name, department_name, student_name):
        super().__init__(name, department_name)
        self.student_name = student_name

    def display_student(self):
        print(f"Student: {self.student_name}")

# Example Usage
student = Student("MIT", "Computer Science", "Charlie")
student.display_university()  # Method from University
student.display_department()  # Method from Department
student.display_student()     # Method from Student

Output

University: MIT
Department: Computer Science
Student: Charlie

Explanation

The Student class inherits from both the Department and University, allowing access to methods at all levels of the inheritance tree.

4. Hierarchical Inheritance

  • Hierarchical Inheritance is the right opposite of multiple inheritance. This means that there are multiple child classes that are derived from a single-parent class.
  • Hierarchical inheritance occurs when numerous derived classes inherit from a single base class. In our case, both Professor and Student derive from Person.

Example

# Base class
class Person:
    def __init__(self, name):
        self.name = name

    def display_name(self):
        print(f"Name: {self.name}")

# Derived classes
class Professor(Person):
    def teach(self):
        print(f"{self.name} is teaching")

class Student(Person):
    def study(self):
        print(f"{self.name} is studying")

# Example Usage
professor = Professor("Dr. Smith")
student = Student("Emily")
professor.display_name()  # Method from Person
professor.teach()         # Method from Professor
student.display_name()    # Method from Person
student.study()           # Method from Student

Output

Name: Dr. Smith
Dr. Smith is teaching
Name: Emily
Emily is studying

Explanation

Professor and Student classes both inherit from Person, letting them use Person's display_name() as well as their own methods.

5. Hybrid Inheritance

  • Hybrid Inheritance is the mixture of two or more different types of inheritance. Here, we can see the many relationships between parent and child classes at multiple levels.
  • Hybrid inheritance is the combination of two or more different forms of inheritance. In our example, TeachingAssistant inherits from both Person and Course, integrating their functionality into a single class.

Example

# Base classes
class Person:
    def __init__(self, name):
        self.name = name

class Course:
    def __init__(self, course_name):
        self.course_name = course_name

# Derived class
class TeachingAssistant(Person, Course):
    def __init__(self, name, course_name, role):
        Person.__init__(self, name)
        Course.__init__(self, course_name)
        self.role = role

    def assist(self):
        print(f"{self.name} is assisting in {self.course_name} as {self.role}")

# Example Usage
ta = TeachingAssistant("David", "Data Science", "Lead TA")
ta.assist()  # Method from TeachingAssistant

Output

David is assisting in Data Science as Lead TA

Explanation

TeachingAssistant combines attributes from both Person and Course, allowing it to perform tasks related to both base classes.

Method Overriding in Inheritance

  • Overriding allows a derived class to provide a specific implementation of a method present in the base class.
  • This allows the derived class to change and extend the behavior of the inherited methods so the method can be put into a context that is more appropriate for the derived class.
  • However, the overriding method in the derived class will have to keep the same name, parameters, and signature as the method in the base class.
  • If necessary, use the super() function to call the base class's method from within the overridden method.

Example

class Animal:
    def speak(self):
        print("Animal speaks")

class Dog(Animal):
    def speak(self):  # Overriding the speak method
        print("Dog barks")

dog = Dog()
dog.speak()  # Outputs: Dog barks

Output

div class="pre-code-wrapper">
Dog barks

Explanation

In this code, the Dog class overrides the Animal class's speak() method, resulting in a new dog-specific implementation. When dog.speak() is used, it invokes the Dog class's talk() method, which returns the string "Dog barks." This demonstrates how method overriding changes inherited behavior.

The super() Function in Python

  • The super() function is a built-in function that returns the objects that represent the parent class.
  • It allows you to reuse the parent class's methods in the child class, which improves code reuse and maintainability.

Example

Let's use our prior university scenario with a Professor and HeadOfDepartment class to explain how to use super().

# Base class
class Professor:
    def __init__(self, name, subject):
        self.name = name
        self.subject = subject

    def teach(self):
        print(f"{self.name} is teaching {self.subject}")

# Derived class using super()
class HeadOfDepartment(Professor):
    def __init__(self, name, subject, department):
        super().__init__(name, subject)  # Call to the base class constructor
        self.department = department

    def manage(self):
        print(f"{self.name} is managing the {self.department} department")

# Example Usage
hod = HeadOfDepartment("Dr. John", "Physics", "Science")
hod.teach()   # Method from Professor class
hod.manage()  # Method from HeadOfDepartment class

Output

Dr. John is teaching Physics
Dr. John is managing the Science department

Explanation

  • __init__() method: This is a Python constructor. It is called automatically when a class instance is created and its attributes are initialized. In this program, both the Professor and HeadOfDepartment classes have their own __init__() methods to initialize the object's state.
  • Constructor in Professor Class: The Professor class's constructor (__init__(self, name, subject)) sets the name and subject attributes for all Professor objects.
  • Constructor in HeadOfDepartment Class: The HeadOfDepartment class's constructor calls the Professor class's constructor via super().__init__(name, subject), ensuring that name and subject are properly initialized before adding the department property specific to HeadOfDepartment. This allows the derived class to extend the underlying class's initialization logic.
  • The HeadOfDepartment class derives from Professor and utilizes super() to invoke the Professor class's constructor, which initializes the name and subject attributes. This allows HeadOfDepartment to use both the Professor's teach() method and its manage() method. The example explains how super() allows for code reuse and expansion in derived classes.

What is a real-world example of inheritance in Python?

If you have a passion for supercars, you'll know that while they all have some similarities, each has its own set of performance specs. Let's look at a basic example of how Python's inheritance can help you simulate supercars efficiently.

  • Consider developing a system to manage information about supercars.
  • You can begin with a generic Vehicle class with common qualities and then expand it to create a Supercar class with specialized features.

Example:

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

    def display_info(self):
        print(f"Vehicle Info: {self.year} {self.make} {self.model}")

# Derived class for supercars
class Supercar(Vehicle):
    def __init__(self, make, model, year, top_speed, horsepower):
        super().__init__(make, model, year)  # Initialize base class attributes
        self.top_speed = top_speed
        self.horsepower = horsepower

    def display_supercar_info(self):
        self.display_info()
        print(f"Top Speed: {self.top_speed} km/h")
        print(f"Horsepower: {self.horsepower} hp")

# Example Usage
supercar = Supercar("Ferrari", "SF90 Stradale", 2023, 340, 1000)
supercar.display_supercar_info()

Output

Vehicle Info: 2023 Ferrari SF90 Stradale
Top Speed: 340 km/h
Horsepower: 1000 hp

Explanation

In this example, inheritance enables the Supercar class to take on properties and methods from the vehicle class. This means that the Supercar inherits the essential attributes of the Vehicle, such as make, model, and year, and can add or change its features, such as top speed and horsepower. The super() function is used to invoke the Vehicle class's constructor, ensuring that the Supercar class is set up with both common and specific properties.
Summary
Python inheritance allows a new class, known as a derived class, to inherit characteristics and functions from an existing base class, which promotes code reuse and efficient development. This lesson introduces the fundamentals of inheritance, including single, multiple, multilevel, hierarchical, and hybrid inheritance, and uses examples to demonstrate method overriding. The advantages of inheritance include mirroring real-world relationships, lowering development and maintenance costs, and offering a clear model structure. Also, consider our Python Programming For Beginners Free course for a better understanding of other Python concepts.

FAQs

Multiple inheritance is a Python feature that allows a child class to inherit from many parent classes. This enables the child class to access properties and methods from all of its parent classes. It allows the integration of functions from various classes into a single class.
Example
# Parent class 1
class Father:
    def __init__(self, father_name):
        self.father_name = father_name

    def show_father(self):
        print(f"Father's Name: {self.father_name}")

# Parent class 2
class Mother:
    def __init__(self, mother_name):
        self.mother_name = mother_name

    def show_mother(self):
        print(f"Mother's Name: {self.mother_name}")

# Child class inheriting from both Father and Mother
class Child(Father, Mother):
    def __init__(self, father_name, mother_name, child_name):
        Father.__init__(self, father_name)
        Mother.__init__(self, mother_name)
        self.child_name = child_name

    def show_child(self):
        print(f"Child's Name: {self.child_name}")

# Example usage
child = Child("John", "Jane", "Alice")
child.show_father()  # Inherited from Father
child.show_mother()  # Inherited from Mother
child.show_child()   # Child class method
In this example, the Child class inherits from both the Father and Mother classes, giving it access to their methods and attributes.

The diamond A multiple inheritance problem occurs when a class inherits from two classes that both derive from the same base class. This might lead to confusion in method resolution because the derived class may inherit the same method via numerous pathways.
Python addresses this issue through the Method Resolution Order (MRO), which uses the C3 linearization algorithm to ensure a consistent order of method resolution. The super() function and MRO specify the order in which methods are inherited and called.
Example
class A:
    def show(self):
        print("Method from class A")

class B(A):
    def show(self):
        print("Method from class B")

class C(A):
    def show(self):
        print("Method from class C")

class D(B, C):  # D inherits from both B and C
    pass

# Example usage
d = D()
d.show()

# To see the MRO
print(D.mro())
In the example, class D inherits from both B and C, which in turn inherit from A. When d.show() is invoked, Python resolves the method using the Method Resolution Order (MRO), which causes it to execute B's display method first, as seen in the MRO list [D, B, C, A].

Python does not explicitly enable interface-based inheritance, a feature found in languages such as Java and C#. In these languages, an interface creates a contract with no implementation, and classes can implement multiple interfaces to ensure that specific methods exist.
However, Python provides similar capability by utilizing abstract base classes (ABCs) from the abc module, but there is no separate concept of "interfaces" as in other languages.

Both the super() function and direct parent class calls provide access to a parent class's methods and attributes, but they serve different purposes and behave differently.

super(): This function is used to call methods from a parent class while following the Method Resolution Order (MRO). It aids in cooperative multiple inheritance by guaranteeing that methods from the next class in the MRO are invoked, which is beneficial for classes with multiple inheritance.

Direct Parent Class Call: Calling a parent class's method directly bypasses the MRO and directly invokes that parent class method, which might be troublesome in a variety of inheritance cases.

class A:
    def show(self):
        print("Method from class A")

class B(A):
    def show(self):
        print("Method from class B")
        super().show()  # Calling method from A using super()

class C(A):
    def show(self):
        print("Method from class C")
        A.show(self)  # Calling method from A directly

class D(B, C):
    pass

# Example usage
d = D()
d.show()

# To see the MRO
print(D.mro())

In this example, d.show() first calls B's show() method, which then uses super() to call C's show() method, followed by A's show() function, as per the MRO [D, B, C, A]. Directly calling A.show(self) in C skips the MRO, displaying a call that does not follow the MRO order.

Single inheritance occurs when a class inherits from only one parent class, resulting in a clear hierarchy. Multiple inheritance allows a class to inherit from two or more parent classes, including features and methods from all of them, which can add confusion and complexity to method resolution. The main difference is the amount of parent classes involved.
Share Article
About Author
Shailendra Chauhan (Microsoft MVP, Founder & CEO at Scholarhat by DotNetTricks)

Shailendra Chauhan is the Founder and CEO at ScholarHat by DotNetTricks which is a brand when it comes to e-Learning. He provides training and consultation over an array of technologies like Cloud, .NET, Angular, React, Node, Microservices, Containers and Mobile Apps development. He has been awarded Microsoft MVP 9th time in a row (2016-2024). He has changed many lives with his writings and unique training programs. He has a number of most sought-after books to his name which has helped job aspirants in cracking tough interviews with ease.
Accept cookies & close this