Inheritance in Python is a fundamental concept in object-oriented programming that allows a class (known as a subclass or derived class) to inherit attributes and methods from another class (known as a parent class or base class). This promotes code reuse and organizational hierarchies in software design.

### Basic Inheritance

Let’s start by creating a simple example with a `Vehicle` class, which will be the parent class for the `Car` class.

“`python
# Parent class
class Vehicle:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year

def start(self):
print(f”{self.make} {self.model} is starting.”)

def stop(self):
print(f”{self.make} {self.model} is stopping.”)

# Subclass
class Car(Vehicle):
def __init__(self, make, model, year, doors):
super().__init__(make, model, year)
self.doors = doors

def open_doors(self):
print(f”Opening {self.doors} doors of the car.”)
“`

In this example, the `Car` class inherits from the `Vehicle` class, inheriting its attributes (`make`, `model`, `year`) and methods (`start`, `stop`). The `Car` class also introduces a new attribute, `doors`, and a method, `open_doors`.

### Overriding Methods

Subclasses can override methods from the parent class to provide specific implementations.

“`python
class ElectricCar(Car):
def __init__(self, make, model, year, doors, battery_size):
super().__init__(make, model, year, doors)
self.battery_size = battery_size

# Overriding the start method
def start(self):
print(f”{self.make} {self.model} is starting silently with a {self.battery_size} kWh battery.”)
“`

Here, `ElectricCar` overrides the `start` method of its parent class, `Car`, to provide a customized message for electric cars.

### Multiple Inheritance

Python allows multiple inheritance, where a class can inherit from more than one parent class. In this scenario, we need to be mindful of the method resolution order (MRO) which dictates the order in which classes are accessed.

“`python
class Flyable:
def fly(self):
print(“This vehicle is flying.”)

class AmphibiousVehicle(Vehicle, Flyable):
def __init__(self, make, model, year):
super().__init__(make, model, year)

def start(self):
print(f”{self.make} {self.model} is starting in water mode.”)

# Create objects
amphibious_vehicle = AmphibiousVehicle(“AmphiCorp”, “AmphiMaster”, 2022)
amphibious_vehicle.start()
amphibious_vehicle.fly()
“`

In this example, `AmphibiousVehicle` inherits from both `Vehicle` and `Flyable`. The `MRO` can be checked using the `__mro__` attribute or the `mro()` method, which shows the order of method resolution.

“`python
print(AmphibiousVehicle.__mro__)
# or using
print(AmphibiousVehicle.mro())
“`

### Method Resolution Order (MRO)

The MRO is determined by the C3 linearization algorithm, which is used to handle complexity when multiple inheritance is involved. The order is generally depth-first, left-to-right, and ensures consistent ordering.

### Using `super()`

The `super()` function is used to call methods from the parent class, allowing access to overridden methods and constructors more effectively in complex hierarchies.

“`python
class ElectricAmphibiousVehicle(AmphibiousVehicle, ElectricCar):
def __init__(self, make, model, year, doors, battery_size):
super().__init__(make, model, year, doors, battery_size)

def start(self):
# Combine behaviors using super()
super().start()
print(“This amphibious vehicle can operate both on land and water, electrically.”)
“`

In this example, `super()` is used to initialize the class, ensuring the correct parent class constructors are called according to the MRO. It’s crucial when you have multiple inheritance to use `super()` to avoid direct parent class name calls, ensuring the MRO is followed.

Inheritance, when used judiciously, can lead to cleaner and more maintainable code by reusing common functionality and providing specific implementations only where necessary.

Scroll to Top