October 13, 2024

Python Inheritance

Inheritance is a key concept in object-oriented programming (OOP) that allows a class to inherit attributes and methods from another class. The class that is inherited from is called the parent class (or superclass), and the class that inherits is called the child class (or subclass). Inheritance promotes code reusability and helps to create a hierarchical relationship between classes.

1. Basic Inheritance

In Python, inheritance is achieved by defining a new class that takes an existing class as its base. The child class inherits all the attributes and methods of the parent class and can also have its own additional attributes and methods.

1.1. Example: Basic Inheritance

# Define a parent class named 'Animal'
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        return f"{self.name} makes a sound"

# Define a child class named 'Dog' that inherits from 'Animal'
class Dog(Animal):
    def speak(self):
        return f"{self.name} barks"

# Create an object of the child class 'Dog'
dog = Dog("Buddy")

# Call the inherited method
print(dog.speak())  # Output: Buddy barks

In this example, the Dog class inherits from the Animal class. The Dog class overrides the speak() method to provide a specific implementation for dogs.

2. Inheritance of Attributes and Methods

The child class inherits all the attributes and methods from the parent class. It can also define its own attributes and methods or override the inherited ones.

2.1. Example: Inheritance with Additional Attributes

# Define a parent class named 'Vehicle'
class Vehicle:
    def __init__(self, make, model):
        self.make = make
        self.model = model
    
    def start_engine(self):
        return f"The engine of the {self.make} {self.model} is starting"

# Define a child class named 'Car' that inherits from 'Vehicle'
class Car(Vehicle):
    def __init__(self, make, model, doors):
        # Initialize the parent class attributes
        super().__init__(make, model)
        self.doors = doors
    
    def display_info(self):
        return f"Car: {self.make} {self.model} with {self.doors} doors"

# Create an object of the child class 'Car'
car = Car("Toyota", "Camry", 4)

# Call the inherited and new methods
print(car.start_engine())    # Output: The engine of the Toyota Camry is starting
print(car.display_info())    # Output: Car: Toyota Camry with 4 doors

In this example, the Car class inherits from the Vehicle class. It adds an additional attribute doors and a new method display_info(), while also utilizing the inherited start_engine() method.

3. Method Overriding

Method overriding occurs when a child class provides a specific implementation of a method that is already defined in its parent class. This allows the child class to modify or extend the behavior of the parent class method.

3.1. Example: Method Overriding

# Define a parent class named 'Bird'
class Bird:
    def fly(self):
        return "Bird is flying"

# Define a child class named 'Penguin' that overrides the 'fly' method
class Penguin(Bird):
    def fly(self):
        return "Penguins can't fly, but they can swim"

# Create an object of the child class 'Penguin'
penguin = Penguin()

# Call the overridden method
print(penguin.fly())  # Output: Penguins can't fly, but they can swim

In this example, the Penguin class overrides the fly() method of the Bird class to provide a specific implementation that reflects the characteristics of penguins.

4. The super() Function

The super() function in Python is used to call a method from the parent class in a child class. It is often used to call the parent class’s constructor and initialize its attributes in the child class.

4.1. Example: Using super() to Call Parent Class Methods

# Define a parent class named 'Employee'
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
    
    def get_details(self):
        return f"Name: {self.name}, Salary: {self.salary}"

# Define a child class named 'Manager' that inherits from 'Employee'
class Manager(Employee):
    def __init__(self, name, salary, department):
        # Call the parent class's constructor
        super().__init__(name, salary)
        self.department = department
    
    def get_details(self):
        # Call the parent class's 'get_details' method
        base_details = super().get_details()
        return f"{base_details}, Department: {self.department}"

# Create an object of the child class 'Manager'
manager = Manager("Alice", 80000, "HR")

# Call the overridden method
print(manager.get_details())  # Output: Name: Alice, Salary: 80000, Department: HR

In this example, the Manager class inherits from the Employee class. The super() function is used to call the parent class’s constructor and the get_details() method to build upon the functionality in the child class.

5. Multiple Inheritance

Python supports multiple inheritance, where a child class can inherit from more than one parent class. This allows a class to inherit attributes and methods from multiple classes.

5.1. Example: Multiple Inheritance

# Define a class named 'Person'
class Person:
    def __init__(self, name):
        self.name = name
    
    def get_name(self):
        return self.name

# Define a class named 'Employee'
class Employee:
    def __init__(self, salary):
        self.salary = salary
    
    def get_salary(self):
        return self.salary

# Define a class named 'Manager' that inherits from both 'Person' and 'Employee'
class Manager(Person, Employee):
    def __init__(self, name, salary, department):
        Person.__init__(self, name)
        Employee.__init__(self, salary)
        self.department = department
    
    def get_details(self):
        return f"Name: {self.name}, Salary: {self.salary}, Department: {self.department}"

# Create an object of the class 'Manager'
manager = Manager("Bob", 90000, "IT")

# Call methods from both parent classes
print(manager.get_name())      # Output: Bob
print(manager.get_salary())    # Output: 90000
print(manager.get_details())   # Output: Name: Bob, Salary: 90000, Department: IT

In this example, the Manager class inherits from both the Person and Employee classes, allowing it to access methods and attributes from both parents.

6. The isinstance() and issubclass() Functions

Python provides two built-in functions to work with inheritance:

  • isinstance(obj, Class): Returns True if the object obj is an instance of the class Class or its subclass.
  • issubclass(SubClass, ParentClass): Returns True if SubClass is a subclass of ParentClass.

6.1. Example: Using isinstance() and issubclass()

# Define a class named 'Animal'
class Animal:
    pass

# Define a class named 'Dog' that inherits from 'Animal'
class Dog(Animal):
    pass

# Create an object of the class 'Dog'
dog = Dog()

# Check if 'dog' is an instance of 'Dog' and 'Animal'
print(isinstance(dog, Dog))      # Output: True
print(isinstance(dog, Animal))   # Output: True

# Check if 'Dog' is a subclass of 'Animal'
print(issubclass(Dog, Animal))   # Output: True

In this example, the isinstance() function checks whether the dog object is an instance of both the Dog and Animal classes. The issubclass() function verifies that Dog is a subclass of Animal.

Inheritance is a powerful feature in Python that allows classes to inherit attributes and methods from other classes, promoting code reuse and hierarchical relationships. By understanding how to use inheritance, method overriding, and the super() function, you can create more complex and modular programs. Additionally, Python’s support for multiple inheritance provides further flexibility in designing class hierarchies.