21
NovInheritance In Python
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
- Single Inheritance
- Multiple Inheritance
- Multilevel Inheritance
- Hierarchical Inheritance
- 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
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
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
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
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
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
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
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())
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.
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())