Python Inheritance


Inheritance is one of the core features of Object-Oriented Programming (OOP), and Python makes it incredibly easy to implement. By allowing one class to inherit the attributes and methods of another class, inheritance promotes code reuse, reduces redundancy, and creates a hierarchical class structure.

In this section, we will explore how inheritance works in Python, discuss the different types of inheritance, and see some practical examples.


What is Inheritance in Python?

In Python, inheritance allows you to define a new class that takes on the properties (attributes) and behaviors (methods) of an existing class. This allows you to extend or customize the existing functionality without modifying the original class.

The class that is inherited from is called the parent class or base class, and the class that inherits from it is called the child class or derived class.

Basic Syntax of Inheritance

class ParentClass:
    # Parent class code
    
class ChildClass(ParentClass):
    # Child class code

Types of Inheritance in Python

Python supports various types of inheritance, each with its own structure and use case. The four main types of inheritance are:

  1. Single Inheritance: A derived class inherits from a single base class.
  2. Multiple Inheritance: A derived class inherits from more than one base class.
  3. Multilevel Inheritance: A class is derived from a class, which is also derived from another class.
  4. Hierarchical Inheritance: Multiple classes inherit from the same base class.
  5. Hybrid Inheritance: A combination of two or more types of inheritance.

Let’s look at each type in detail.


1. Single Inheritance

Single inheritance is the simplest form, where a derived class inherits from a single base class.

Example: Single Inheritance

class Animal:
    def speak(self):
        print("Animal makes a sound")
        
class Dog(Animal):
    def bark(self):
        print("Woof!")

# Creating an object of Dog class
dog = Dog()
dog.speak()  # Inherited method from Animal class
dog.bark()   # Method from Dog class

Explanation:

  • The Dog class inherits from the Animal class, meaning that the Dog class automatically has access to the speak method from the Animal class.
  • In addition to inherited behavior, the Dog class can define its own methods like bark.

2. Multiple Inheritance

In multiple inheritance, a class can inherit from more than one base class. This allows the child class to inherit features from multiple classes.

Example: Multiple Inheritance

class Animal:
    def speak(self):
        print("Animal makes a sound")
        
class Dog:
    def bark(self):
        print("Woof!")

class Bulldog(Animal, Dog):
    def growl(self):
        print("Bulldog growls")

# Creating an object of Bulldog class
bulldog = Bulldog()
bulldog.speak()  # Inherited from Animal
bulldog.bark()   # Inherited from Dog
bulldog.growl()  # Defined in Bulldog

Explanation:

  • The Bulldog class inherits from both the Animal class and the Dog class.
  • It can use methods from both parent classes (speak from Animal and bark from Dog), as well as define its own methods (growl).

Caution:

Multiple inheritance can sometimes lead to complexities, especially if different base classes have methods with the same name (this is called the diamond problem).


3. Multilevel Inheritance

In multilevel inheritance, a class is derived from another class, which is itself derived from another class. It forms a chain of inheritance.

Example: Multilevel Inheritance

class Animal:
    def speak(self):
        print("Animal makes a sound")

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

class Bulldog(Dog):
    def growl(self):
        print("Bulldog growls")

# Creating an object of Bulldog class
bulldog = Bulldog()
bulldog.speak()  # Inherited from Animal
bulldog.bark()   # Inherited from Dog
bulldog.growl()  # Defined in Bulldog

Explanation:

  • The Bulldog class inherits from Dog, which itself inherits from Animal.
  • The Bulldog object can access methods from both Dog and Animal classes, forming a chain of inheritance.

4. Hierarchical Inheritance

In hierarchical inheritance, multiple classes inherit from a single base class.

Example: Hierarchical Inheritance

class Animal:
    def speak(self):
        print("Animal makes a sound")

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

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

# Creating objects of Dog and Cat classes
dog = Dog()
dog.speak()  # Inherited from Animal
dog.bark()   # Defined in Dog

cat = Cat()
cat.speak()  # Inherited from Animal
cat.meow()   # Defined in Cat

Explanation:

  • Both the Dog and Cat classes inherit from the Animal class.
  • This allows both classes to use the speak method from the Animal class while also having their own specific methods.

5. Hybrid Inheritance

Hybrid inheritance is a combination of two or more types of inheritance. It can combine, for example, multiple and multilevel inheritance into one system.

Example: Hybrid Inheritance

class Animal:
    def speak(self):
        print("Animal makes a sound")

class Mammal(Animal):
    def has_fur(self):
        print("Mammals have fur")

class Bird(Animal):
    def can_fly(self):
        print("Birds can fly")

class Bat(Mammal, Bird):
    def fly_and_speak(self):
        self.speak()
        self.can_fly()
        print("Bats can also fly")

# Creating an object of Bat class
bat = Bat()
bat.speak()     # Inherited from Animal
bat.has_fur()   # Inherited from Mammal
bat.can_fly()   # Inherited from Bird
bat.fly_and_speak()  # Method defined in Bat

Explanation:

  • The Bat class inherits from both Mammal and Bird, which themselves inherit from Animal.
  • This is an example of hybrid inheritance, where different inheritance types combine to form a more complex hierarchy.

Method Resolution Order (MRO) and the Diamond Problem

When a class inherits from multiple classes (multiple inheritance), Python uses a mechanism called Method Resolution Order (MRO) to determine the order in which methods should be inherited. This can be crucial when a method exists in more than one class in the inheritance chain.

Example of MRO and Diamond Problem

class A:
    def hello(self):
        print("Hello from A")

class B(A):
    def hello(self):
        print("Hello from B")

class C(A):
    def hello(self):
        print("Hello from C")

class D(B, C):
    pass

# Creating an object of D
d = D()
d.hello()  # Which hello method will be called?

Explanation:

In the above example, D inherits from both B and C. The method hello is defined in both B and C. Python will follow the MRO to determine the order in which it looks for the method. You can see the MRO by calling D.__mro__.

print(D.__mro__)