Python Inheritance

Inheritance is a fundamental concept in object-oriented programming (OOP) that allows a class (known as the child or derived class) to inherit attributes and methods from another class (known as the parent or base class). This helps in creating a hierarchical relationship between classes and promotes code reuse.

Key Concepts

Parent Class (Base Class): The class whose attributes and methods are inherited by another class.

Child Class (Derived Class): The class that inherits attributes and methods from the parent class.

Method Overriding: The child class can provide a specific implementation of a method that is already defined in its parent class.

Super Function: Used to call methods from the parent class from within the child class.

Types of Inheritance

Single Inheritance

Single inheritance is the simplest form of inheritance where a child class inherits from a single parent class. This type helps in establishing a straightforward parent-child relationship.

class Animal:
    def eat(self):
        print("Eating")

class Dog(Animal):
    def bark(self):
        print("Barking")

# Creating an instance of Dog
dog = Dog()
dog.eat()     # Inherited from Animal
dog.bark()     # Defined in Dog

In this example, Dog inherits the eat method from Animal and has its own method bark.

Multiple Inheritance

In multiple inheritance, a child class inherits from more than one parent class. This allows a class to combine functionality from multiple sources.

class Father:
    def skills(self):
        print("Gardening, Painting")

class Mother:
    def skills(self):
        print("Cooking, Sewing")

class Child(Father, Mother):
    def skills(self):
        print("Child's skills")
        Father.skills(self)     
        Mother.skills(self)     

# Creating an instance of Child
child = Child()
child.skills()

Multilevel Inheritance

Multilevel inheritance involves a hierarchy of classes where a class inherits from another class, which itself is derived from another class. This forms a chain of inheritance.

class Grandparent:
    def speak(self):
        print("Speaking")

class Parent(Grandparent):
    def walk(self):
        print("Walking")

class Child(Parent):
    def play(self):
        print("Playing")

# Creating an instance of Child
child = Child()
child.speak()     # Inherited from Grandparent
child.walk()     # Inherited from Parent
child.play()     # Defined in Child

In this example, Child inherits from Parent, which in turn inherits from Grandparent.

Hierarchical Inheritance

Hierarchical inheritance occurs when multiple classes inherit from a single parent class. This allows different classes to share the same base functionality.

class Vehicle:
    def start(self):
        print("Vehicle starting")

class Car(Vehicle):
    def drive(self):
        print("Driving car")

class Bike(Vehicle):
    def ride(self):
        print("Riding bike")

# Creating instances of Car and Bike
car = Car()
bike = Bike()
car.start()     # Inherited from Vehicle
car.drive()     # Defined in Car
bike.start()     #Inherited from Vehicle
bike.ride()     # Defined in Bike

Here, both Car and Bike inherit the start method from Vehicle and have their own specific methods.

Multiple Inheritance with Method Resolution Order (MRO)

In multiple inheritance, Python uses the C3 linearization algorithm to determine the method resolution order. This ensures a consistent and predictable order of method calls when dealing with multiple base classes.

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

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

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

class D(B, C):
    pass

# Creating an instance of D
d = D()
d.method() # Output will be "Method from B"

In this example, class D inherits from both B and C. According to the MRO, Python will use the method from B because it is listed first.

Additional Concepts

Method Overriding: When a child class provides a specific implementation for a method that is already defined in its parent class, this is called method overriding. The child class’s method overrides the parent class’s method.

class Parent:
    def greet(self):
        print("Hello from Parent")

class Child(Parent):
    def greet(self):
        print("Hello from Child")

# Creating an instance of Child
child = Child()
child.greet()     # Output will be "Hello from Child"

Using super():The super() function is used to call a method from the parent class within a child class. This is particularly useful when you want to extend or modify the functionality of an inherited method.

class Parent:
    def __init__(self):
        print("Parent __init__")

class Child(Parent):
    def __init__(self):
        super().__init__()
        print("Child __init__")

# Creating an instance of Child
child = Child()
# Output:
# Parent __init__
# Child __init__

Inheritance helps in creating a more organized and hierarchical class structure, promoting code reuse, and allowing for more flexible and maintainable code.