Python Inheritance
Inheritance is an object-oriented feature that allows a class to acquire attributes and methods from another class.
The parent class is the original class that defines these attributes and methods. It is also known as base or superclass.
The child class is the new class that inherits from the parent class and can use or extend its functionality. It is also known as derived or subclass.
Why Use Inheritance?
Inheritance offers several advantages:
- Code reusabilty: You can use reuse existing code from a parent class instead of writing it again.
- Easy Maintenance: When you update the parent class, the changes apply automatically to child classes.
- Extensibility: You can add or change features without touching the parent class.
- Better organization: You can structure your code to reflect real-world relationships.
- Polymorphism: You can work with different child classes using the same parent interface.
Basic Syntax of Inheritance
To inherit from a class, you pass the parent class as an argument in the definition of the child class.
class ParentClass:
# attributes and methods of parent class
pass
class ChildClass(ParentClass):
# attributes and method child class
pass
Here ChildClass automatically gets access to all public methods and attributes of ParentClass.
Note: Use the pass statement if you don’t want to define any attributes and methods yet.
Basic Inheritance Example
class Animal:
def speak(self):
print("The animal makes a sound")
class Dog(Animal):
def bark(self):
print("The dog barks")
dog = Dog()
dog.speak() # Inherited method
dog.bark() # Child's own method
Output:
The animal makes a sound
The dog barks
In this example, we define a class called Animal that represents a general animal and contains a method named speak, which prints a generic sound message. We then create another class called Dog, that inherits from the Animal class.
By inheriting from Animal class, the Dog class automatically gains access to all the methods and attributes (in our case we don’t have any) defined in Animal class, including the speak method, without needing to redefine it. In addition to the inherited behavior, the Dog class also defines its own method bark, which represents behavior specific to dogs.
When we created an instance (object) of the Dog class, we can call both the inherited speak method and the bark method. This demostrates how inheritance allows a child class to reuse and extend the functionality of a parent class.
Overriding Methods in Python Inheritance
A child class can override methods from the parent class.
For example:
class Animal:
def speak(self):
print("The animal makes a sound")
class Dog(Animal):
def speak(self):
print("The dog barks")
dog = Dog()
dog.speak() # Output: The dog barks
In this example, we override the speak() method defined in the Animal class in the Dog subclass, allowing Dog class to provide its own implementation of the method.
The super() Function
The super() function allows a child class to call methods defined in its parent class.
For example:
class Animal:
def speak(self):
print("The animal makes a sound")
class Dog(Animal):
def bark(self):
super().speak()
print("The dog barks")
dog = Dog()
dog.bark()
In this example, inside the bark() method of the Dog class, we use super() to call the speak() method defined in the parent Animal class. This allows us to reuse the behavior from Animal class while extending it by adding the dog’s own specific action, showing how inheritance helps us build on existing functionality.
Using __init__() in Inheritance
When you define an __init__() method in a child class, it overrides the parent class’s __init__() method. It means the child class takes full control of the initialization process, and the parent’s __init__() will not run automatically.
If you still want the parent class to set up its attributes, you need to explicitly call super().__init__() within the child’s __init__() method.
For example:
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name)
self.breed = breed
dog = Dog("Max", "Labrador")
print(dog.name) # Output: Max
print(dog.breed) # Output: Labrador
Types of Inheritance in Python
Python supports several types of inheritance:
(1) Single inheritance
A child class inherits from only one parent class. The example we discussed above is an example of a single inheritance because the child class inherits from only one parent class.
(2) Multiple inheritance
A child class inherits from more than one parent class.
For example:
class Father:
def skills(self):
print("Gardening")
def repairing(self):
print("Fixing household items")
class Mother:
def skills(self):
print("Cooking")
class Child(Father, Mother):
pass
child = Child()
child.skills() # Uses Father's skills() due to MRO
child.repairing() # Inherited from Father
Output:
Gardening
Fixing household items
In this example, the Child class inherits from both the Father and Mother classes. The Father class defines two methods: skills() and repairing(), while the Mother class defines its own version of the skills() method.
When the Child class is created, it automatically gains access to the methods of both parent classes. Since the Child class does not override any methods, Python follows the Method Resolution Order (MRO) to determine which parent method to call when there is a name conflict. Because Father class is listed before Mother class in the inheritance list(class Child(Father, Mother)), the skills() method from the Father class is called when child.skills() is executed.
Additionally, the repairing() method is only defined in the Father class, so the Child object can access it directly without any ambiguity. This example highlights how Python handles method conflicts in multiple inheritance and how MRO determines the order in which parent classes are searched.
(3) Multilevel Inheritance
A derived class inherits from another derived class, forming a chain or hierarchy of classes.
For example:
class Grandparent:
def house(self):
print("Owns a house")
class Parent(Grandparent):
pass
class Child(Parent):
pass
child = Child()
child.house() # Output: Owns a house
In this example, the Grandparent class defines a method called house(). The Parent class inherits from the Grandparent class, and the Child class further inherits from Parent class.
Even though neither the Parent nor the Child class defines any new methods (both use pass), the Child class still has access to the house() method. This happens because inheritance allows a subclass to access all public methods of its parent classes across multiple levels.
When child.house() is called, Python looks for the house() method in the Child class first. Since it s not found there, Python continues searching up the inheritance hierarchy-first in the Parent class, and then in the Grandparent class, where the method is defined. As a result, the house() method from the Grandparent class is executed, and the output is displayed.
(4) Hierarchical Inheritance
Multiple child classes inherit from a single parent class.
For example:
class Parent:
def house(self):
print("Owns a house")
class Child1(Parent):
pass
class Child2(Parent):
pass
child1 = Child1()
child2 = Child2()
child1.house() # Output: Owns a house
child2.house() # Output: Owns a house
In this example, both the Child1 and Child2 classes inherit from the Parent class. Therefore objects of both classes have access to the house() method defined in the Parent class.
(5) Hybrid Inheritance
A combination of two or more types of inheritance.
For example:
class Animal:
def eat(self):
print("Animal can eat")
# Derived class 1
class Mammal(Animal):
def walk(self):
print("Mammal can walk")
# Derived class 2
class Bird(Animal):
def fly(self):
print("Bird can fly")
# Hybrid Inheritance (inheritance from both both Mammal and Bird)
class Bat(Mammal, Bird):
def sleep(self):
print("Bat sleeps upside down")
bat = Bat()
bat.eat() # from Animal
bat.walk() # from Mammal
bat.fly() # from Bird
bat.sleep() # from Bat itself
Output:
Animal can eat
Mammal can walk
Bird can fly
Bat sleeps upside down
In this example, Animal class is the base class and defines a eat() method. The Mammal and Bird classes are derived classes that inherit from Animal class. The Mammal class adds a walk() method, while the Bird class adds a fly() method.
The Bat class inheirts from both Mammal and Bird classes, making it a hybrid subclass. Additionaly, it defines its own method sleep(). This means an instance of Bat can use methods from Animal, Mammal, Bird, as well as its own, demostrating Python’s support for multiple inheritance.