Exploring Python Inheritance With Practical Examples

Inheritance is a fundamental concept in object-oriented programming that allows a new class (subclass/derived class) to inherit attributes and methods from an existing class (base class/parent class).

Python supports inheritance, providing a powerful mechanism for code reuse and building relationships between classes. In this article, we'll explore Python inheritance through practical examples.

1. Basic Inheritance:

Let's start with a simple example involving a base class Vehicle and a derived class Car. The Car class inherits attributes and methods from the Vehicle class.

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

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

# Car class inherits from Vehicle
class Car(Vehicle):
    def __init__(self, make, model, year, num_doors):
        # Call the constructor of the base class
        super().__init__(make, model, year)
        self.num_doors = num_doors

    def display_info(self):
        # Override the display_info method in the base class
        print(f"{self.year} {self.make} {self.model} ({self.num_doors} doors)")

# Create instances of Car
car1 = Car("Toyota", "Camry", 2022, 4)
car2 = Car("Tesla", "Model 3", 2022, 2)

# Call display_info method
car1.display_info()  # Output: 2022 Toyota Camry (4 doors)
car2.display_info()  # Output: 2022 Tesla Model 3 (2 doors)

2. Multiple Inheritance:

Python allows a class to inherit from multiple base classes. Here's an example with classes Engine and ElectricVehicle combined with the previous Vehicle class.

class Engine:
    def start(self):
        print("Engine started")

    def stop(self):
        print("Engine stopped")

class ElectricVehicle(Vehicle, Engine):
    def __init__(self, make, model, year, battery_capacity):
        # Call constructors of base classes
        Vehicle.__init__(self, make, model, year)
        Engine.__init__(self)
        self.battery_capacity = battery_capacity

    def display_info(self):
        print(f"{self.year} {self.make} {self.model} (Battery: {self.battery_capacity} kWh)")

# Create an ElectricVehicle instance
electric_car = ElectricVehicle("Nissan", "Leaf", 2022, 40)

# Call methods
electric_car.display_info()  # Output: 2022 Nissan Leaf (Battery: 40 kWh)
electric_car.start()         # Output: Engine started
electric_car.stop()          # Output: Engine stopped

3. Method Resolution Order (MRO):

In cases of multiple inheritance, Python follows the C3 linearization algorithm to determine the method resolution order (MRO).

The __mro__ attribute can be used to inspect the MRO.

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

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

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

class D(B, C):
    pass

# Create an instance of D
d_instance = D()

# Call the show method
d_instance.show()  # Output: B

# Print the method resolution order
print(D.__mro__)  # Output: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

4. Inheriting from Built-in Classes:

You can also inherit from built-in classes like list or dict to create custom classes with specific behaviors.

class CustomList(list):
    def display_info(self):
        print(f"Custom List: {self}")

# Create an instance of CustomList
custom_list = CustomList([1, 2, 3])

# Call methods
custom_list.append(4)
custom_list.display_info()  # Output: Custom List: [1, 2, 3, 4]

Conclusion:

Inheritance is a powerful feature in Python that allows classes to reuse and extend the functionality of other classes.

It promotes code reusability, enhances modularity, and facilitates the creation of more specialized classes.

Understanding the concepts of inheritance, method overriding, and method resolution order is crucial for effective object-oriented programming in Python.

As you design and structure your programs, consider the relationships between classes and how inheritance can be leveraged to build a cohesive and scalable codebase.