Inheritance in Python

Inheritance is a fundamental concept in object-oriented programming that allows one class (the child class) to derive the properties and methods of another class (the parent class). This promotes code reusability and enhances modularity.

Understanding Inheritance

When a class inherits from another, it gains access to the parent class’s methods and attributes. The child class can also override or extend the functionalities of the parent class.

Syntax

</>
Copy
class Parent:
    # Parent class code

class Child(Parent):
    # Child class code

Examples

1. Basic Inheritance Example

In this example, we create a parent class Animal and a child class Dog. The child class inherits the properties and methods of the parent class.

We define the Animal class with a method make_sound(). The Dog class inherits from Animal, meaning it automatically has access to make_sound(). This allows us to create objects of Dog and use methods from Animal without redefining them.

</>
Copy
# Defining the Parent class
class Animal:
    def make_sound(self):
        print("Animal makes a sound")

# Defining the Child class inheriting from Animal
class Dog(Animal):
    pass

# Creating an instance of Dog
dog = Dog()

# Calling the inherited method
dog.make_sound()

Output:

Animal makes a sound

Since Dog inherits from Animal, it automatically has access to the make_sound() method. Even though we did not define make_sound() in Dog, it still works.

2. Overriding Parent Class Methods

In some cases, we may want to change the behavior of a method inherited from the parent class. This is called method overriding.

Here, we define the Animal class with a make_sound() method. The Dog class overrides this method with its own implementation. This means when we call make_sound() on a Dog object, Python will use the method from Dog instead of the one from Animal.

</>
Copy
# Parent class
class Animal:
    def make_sound(self):
        print("Animal makes a sound")

# Child class overriding the method
class Dog(Animal):
    def make_sound(self):
        print("Dog barks")

# Creating an instance of Dog
dog = Dog()

# Calling the overridden method
dog.make_sound()

Output:

Dog barks

Even though Dog is inheriting from Animal, it has its own version of make_sound(), which takes precedence over the inherited one.

3. Using the super() Function

The super() function allows us to call a method from the parent class inside a child class. This is useful when extending a method rather than completely replacing it.

Here, the Dog class still has its own make_sound() method, but inside it, we use super().make_sound() to first call the parent class’s method before adding extra functionality.

</>
Copy
# Parent class
class Animal:
    def make_sound(self):
        print("Animal makes a sound")

# Child class extending the method using super()
class Dog(Animal):
    def make_sound(self):
        super().make_sound()  # Calling the parent class method
        print("Dog barks")

# Creating an instance of Dog
dog = Dog()

# Calling the extended method
dog.make_sound()

Output:

Animal makes a sound
Dog barks

Using super(), we ensure that the Animal class’s make_sound() method is executed before the Dog class’s custom behavior is added.

4. Inheriting the __init__ Constructor

When a child class has its own constructor, it does not automatically inherit the parent’s constructor. We can use super() to call the parent’s constructor and initialize attributes properly.

Here, the Animal class has an __init__ method that initializes a species attribute. The Dog class defines its own __init__ but still calls super().__init__() to initialize the inherited attributes properly.

</>
Copy
# Parent class
class Animal:
    def __init__(self, species):
        self.species = species

# Child class calling the parent constructor
class Dog(Animal):
    def __init__(self, name):
        super().__init__("Dog")  # Call parent constructor
        self.name = name

# Creating an instance of Dog
dog = Dog("Buddy")

# Print attributes
print("Species:", dog.species)
print("Name:", dog.name)

Output:

Species: Dog
Name: Buddy

Using super().__init__("Dog"), we ensure that the Animal class properly initializes the species attribute before we add the name attribute specific to Dog.