Python Inheritance

Python Inheritance

Inheritance is a fundamental concept in object-oriented programming (OOP) that allows one class (the child class) to inherit the attributes and methods from another class (the parent class). This enables code reuse, where the child class can leverage functionality from the parent class and can also define additional behavior or override inherited methods.

1. Basic Inheritance Syntax

To implement inheritance in Python, you define a class that inherits from another class by specifying the parent class in parentheses.

Syntax:

class ChildClass(ParentClass):
    # Child class code

The ChildClass inherits all the attributes and methods of the ParentClass.

2. Example of Inheritance

Here’s a basic example where the Dog class inherits from the Animal class.

Example:

# Parent Class
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name} makes a sound")

# Child Class inheriting from Animal
class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)  # Call the parent class constructor
        self.breed = breed

    def speak(self):
        print(f"{self.name} barks!")

# Create an object of the Dog class
dog = Dog("Buddy", "Golden Retriever")
dog.speak()  # Output: Buddy barks!

In this example:

  • The Dog class inherits from the Animal class.
  • The super() function is used in the Dog class constructor to call the parent class (Animal) constructor, initializing the name attribute.
  • The speak method is overridden in the Dog class to provide specific behavior for dogs.

3. Using super() in Inheritance

The super() function is used to call methods from the parent class, particularly the constructor (__init__) or other methods that you want to reuse in the child class.

Example with super():

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print(f"{self.name} makes a sound")

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)  # Call the parent class constructor
        self.breed = breed
    
    def speak(self):
        super().speak()  # Call the parent class speak method
        print(f"{self.name} barks!")

dog = Dog("Max", "Bulldog")
dog.speak()  # Output: Max makes a sound
             #         Max barks!

In this example:

  • super().__init__(name) is used to call the parent class (Animal) constructor.
  • super().speak() is used to call the speak() method of the parent class, followed by adding behavior specific to Dog.

4. Overriding Methods

A child class can override methods of the parent class to modify or extend the functionality. If the child class provides its own implementation of a method, the parent class’s version is no longer used.

Example:

class Animal:
    def speak(self):
        print("Animal makes a sound")

class Dog(Animal):
    def speak(self):
        print("Dog barks")

# Create objects
animal = Animal()
dog = Dog()

animal.speak()  # Output: Animal makes a sound
dog.speak()     # Output: Dog barks

In this example, the speak method is overridden in the Dog class to provide a specific implementation for dogs.

5. Inheritance Hierarchy

A child class can also inherit from another child class, forming a multi-level inheritance hierarchy.

Example of Multi-level Inheritance:

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name} makes a sound")

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)
        self.breed = breed
    
    def speak(self):
        print(f"{self.name} barks!")

class Puppy(Dog):
    def __init__(self, name, breed, age):
        super().__init__(name, breed)
        self.age = age
    
    def speak(self):
        print(f"{self.name} barks softly!")

puppy = Puppy("Charlie", "Beagle", 1)
puppy.speak()  # Output: Charlie barks softly!

In this example:

  • Puppy inherits from Dog, which in turn inherits from Animal.
  • The Puppy class adds an age attribute and overrides the speak method.

6. Multiple Inheritance

Python supports multiple inheritance, which means a child class can inherit from more than one parent class. However, this can create complexity, especially if multiple parent classes have methods with the same name. Python resolves these conflicts using the Method Resolution Order (MRO).

Example of Multiple Inheritance:

class Animal:
    def speak(self):
        print("Animal makes a sound")

class Dog:
    def speak(self):
        print("Dog barks")

class Hybrid(Animal, Dog):
    def speak(self):
        print("Hybrid speaks differently")
        super().speak()  # Calls the first parent class method in MRO

hybrid = Hybrid()
hybrid.speak()  # Output: Hybrid speaks differently
                #         Animal makes a sound

In this example:

  • The Hybrid class inherits from both Animal and Dog.
  • When speak() is called on a Hybrid object, Python uses the MRO to determine which parent class’s method to invoke.

7. The Method Resolution Order (MRO)

In the case of multiple inheritance, Python follows a specific order to search for a method in the class hierarchy. This order is defined by the C3 linearization algorithm, and can be checked using the mro() method.

Example of MRO:

class A:
    def speak(self):
        print("Class A speaks")

class B(A):
    def speak(self):
        print("Class B speaks")

class C(A):
    def speak(self):
        print("Class C speaks")

class D(B, C):
    pass

# Check MRO for class D
print(D.mro())

Output:

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

In this example, the MRO for class D indicates the order in which Python will search for methods: D, B, C, A, and finally the base object class.

8. Private and Protected Members in Inheritance

  • Protected members: Members that are intended to be protected (for internal use by subclasses) can be defined with a single underscore (_), but this is a convention and doesn’t prevent access outside the class.
  • Private members: Members that should not be accessed outside the class are defined with double underscores (__). Python performs name mangling to make these variables harder to access.

Example with Private and Protected Members:

class Parent:
    def __init__(self):
        self._protected = "This is protected"
        self.__private = "This is private"

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

    def show(self):
        print(self._protected)
        # print(self.__private)  # This will cause an error

child = Child()
child.show()

In this example:

  • self._protected can be accessed by subclasses, but self.__private is not directly accessible due to name mangling.

Summary of Inheritance Concepts:

  1. Inheritance: The mechanism of creating a new class from an existing class.
  2. Child Class: The class that inherits from a parent class.
  3. Parent Class: The class that is inherited from.
  4. Method Overriding: The child class can provide its own implementation of a method.
  5. super(): Used to call methods from the parent class.
  6. Multi-level Inheritance: Inheriting from a class that itself inherits from another class.
  7. Multiple Inheritance: A class can inherit from more than one parent class.
  8. Method Resolution Order (MRO): The order in which Python searches for methods in a class hierarchy.
Leave a Reply 0

Your email address will not be published. Required fields are marked *