In this tutorial, you will master everything about the basic concepts of object-oriented programming like inheritance, encapsulation, etc with their syntax and examples. Moreover, you will walk through different types of inheritance in OOPs.
The object-oriented programming approach is the most important and universally accepted programming approach as it completely relies on the objects and classes, which encourages modularity and software reusability.
Four building blocks of object-oriented programming are :
This tutorial will ride through each methodology in detail. So let’s start our ride with Inheritance.
Inheritance can be defined as a process through which one class acquires the features(attributes and methods) of an existing class without modifying it. The class which inherits the features is referred to as child class or derived class and the class from which the features inherited is referred to as parent class or base class. In other words, the newly formed class is the child class while the existing class is known as the parent class.
For instance, in the real world, a father and mother denote the parent class while their kids denote the child class. A kid has acquired several features from their parents and at the same time, the kid has got some unique features that the parents may not have. In programming terms, we can say that a child class acquires all the attributes and methods of a parent class, but at the same time child class holds its own unique characteristics.
The Syntax of inheritance is as follows:
class Parent_class:
Body of parent_class
class Child_class(Parent_class):
Body of Child_class
In python, Inheritance is divided into five types. They are :
Single inheritance is one of the simplest and easiest types of inheritance. In single inheritance, the child class inherits all the attributes and methods in the parent class. This enables code reusability and modularity.
In this case, class A is the parent class and class B is the child class. Class B has its own unique attributes and method even then it inherits the attributes and methods of class A.
The syntax of single inheritance is as follows:
class A:
pass
class B(A):
pass
Observe the example to find the area of the rectangle. Here, Shape is the parent class and Rect is the child class. In parent class, we have one function to display()
which displays the length and breadth of the rectangle. And in the child class, we have defined the function area()
to find the area of the rectangle and print the output.
class Shape: #Parent Class
def __init__(self,name,length,breadth):
self.name=name
self.l=length
self.b=breadth
def display(self):
print("Length is :",self.l)
print("Breadth is :",self.b)
class Rect(Shape): #Child Class
def area(self):
a=self.l*self.b
print("Area of",self.name,"is",a)
ob = Rect('Rectangle',10,20)
ob.display()
ob.area()
p>Output:
Length is : 10 Breadth is : 20 Area of Rectangle is 200
When you observe the example you will notice the following:
Multilevel inheritance is a type of inheritance where a class is created from a derived class which itself inherits a base class. A multilevel inheritance shows the possibility of inheriting from a derived class or child class. So a minimal multilevel inheritance is 3 tier structure with a child class that inherits features from a derived class which in turn inherits the properties from a superclass.
Here, Class A is the superclass, Class B is the derived Class and Class C is the child class. Class C can inherit all the properties of Class B and Class A while class B can only inherit features of Class A.
The syntax is as follows :
class A:
pass
class B(A):
pass
class C(B):
pass
Let’s see how our previous example changed. Here we have created a new class called Square which is the child of class Rect.
class Shape: #Superclass
def __init__(self,name,length,breadth):
self.name=name
self.l=length
self.b=breadth
def display(self):
print("Length is :",self.l)
print("Breadth is :",self.b)
class Rect(Shape): #Derived Class
def area(self):
a=self.l*self.b
print("Area of",self.name,"is",a)
class Square(Rect): #Child Class
def peri(self):
p =4*self.l
print("Perimeter of",self.name,"is",p)
obs = Square('Square',20,20)
obs.display()
obs.area()
obs.peri()
Output:
Length is : 20 Breadth is : 20 Area of Square is 400 Perimeter of Square is 80
You will notice the following points from the example:
Note: A child class can access a superclass while the reverse is not possible.
Hierarchical Inheritance is a type of inheritance where more than one child class are created from the base class.
The above figure illustrates the hierarchical structure where Class B and Class C inherit the properties of Class A, though both have their own unique features.
The syntax is as follows :
class A:
pass
class B(A):
pass
class C(A):
pass
Now let's change our class shape and see how hierarchical inheritance works. In this case, we have one base class named Shape and two child classes namely Rect and Tri. Both classes inherit the display()
function from the Shape class to print the length and breadth. In Rect class, we find the area of the rectangle while in Tri class we find the area of the triangle using two different functions R_area()
and T_area()
.
class Shape:
def __init__(self,name,length,breadth):
self.name=name
self.l=length
self.b=breadth
def display(self):
print("Length is :",self.l)
print("Breadth is :",self.b)
class Rect(Shape):
def R_area(self):
a=self.l*self.b
print("Area of",self.name,"is",a)
class Tri(Shape):
def T_area(self):
a=0.5*self.l*self.b
print("Area of",self.name,"is",a)
obr = Rect('Rectangle',10,20)
obr.display()
obr.R_area()
obt = Tri('Triangle',10,20)
obt.display()
obt.T_area()
Output:
Length is : 10 Breadth is : 20 Area of Rectangle is 200 Length is : 10 Breadth is : 20 Area of Triangle is 100.0
Here since we use two separate child classes we need to create two objects. obr is the object for class Rect and obt is the object for Tri. Using obr we have called the function display() which is a feature of base class shape. Similarly, the object obt calls the function display()
. So here two different objects inherit the same features of their base class. Besides these, using the objects both classes have called their own function R_area()
and T_area()
defined inside the classes Rect and Tri respectively.
When a child class is created from two base classes then it is called Multiple Inheritance. As the name says, the derived class inherits features of two different classes.
The figure depicts the inheritance of properties of Class A and Class B by class C. Here class A and class B are the base classes of Class C which can acquire the attributes and methods of both classes. In real world, a child inherits the features of both mother and father.
The syntax is as follows :
class A:
pass
class B:
pass
class C(A , B):
pass
The following example shows the working of Multiple inheritances without using super()
in python. In this example, we have two base classes namely, Mom class and Dad class and our child class is Kid. The Kid class can inherit features of Mom class and Dad class using its object obk as given in the example. Each class has unique methods defined as feature_m
,feature_d
and feature_k
.
class Mom:
def feature_m(self):
print("Iam your mom")
class Dad:
def feature_d(self):
print("Iam your dad")
class Kid(Mom,Dad):
def feature_k(self):
print("Iam the Kid")
obk = Kid()
obk.feature_m()
obk.feature_d()
obk.feature_k()
Output:
Iam your mom Iam your dad Iam the Kid
Multiple inheritances gives the freedom for a child class to inherit as many base classes as it can. So while using multiple inheritances what will happen if multiple base classes use the same name for methods. Let’s check out the example to understand it wisely.
class Mom:
def feature(self):
print("Iam your mom")
class Dad:
def feature(self):
print("Iam your dad")
class Kid(Mom,Dad):
def feature(self):
print("Iam the Kid")
obk = Kid()
obk.feature()
Output:
Iam the Kid
Here we made a slight change to our prior example. All methods have the same name. The output we received is ‘I am the kid’ which is defined inside the feature method in child class Kid. Why is it so? This is because the object of a child class is created here and it always calls its own methods first.
So what should we do to access the features of its parent class? Python offers a keyword called super to sort this issue. The below program will clarify this:
class Mom:
def feature(self):
print("I am your mom")
class Dad:
def feature(self):
print("I am your dad")
class Kid(Mom,Dad):
def feature(self):
super().feature()
print("I am the Kid")
obk = Kid()
obk.feature()
Output:
I am your mom I am the Kid
A small change in the program gives you a new result. super().feature() calls the method in superclass Mom. Have you wondered why it hasn't called the method in its other superclass Dad? The following session will give you the appropriate answer.
Method Resolution Order, commonly referred to as MRO in python, is the set of rules used to search the order in which python looks for a method in the class hierarchy. The order in which derived classes. The order in which the methods are called is known as linearization.
MRO plays a crucial role while dealing with multi-level inheritance scenarios, especially when it comes to multiple inheritances. The reason for this is that when multiple classes in the hierarchy possess the same method, python first searches for the given method or attribute in the current class and if it is not found then it searches its parent classes in the depth-first, left to right order. Each class in the hierarchy is searched once until it reaches its ultimate base class i.e. object class. This means that in python the base class for any user-defined or built-in class is object class. You will get a clear picture in the below example.
Python provides two possible ways to view the MRO of a class are :
class Mom:
def feature(self):
print("I am your mom")
class Dad:
def feature(self):
print("I am your dad")
class Kid(Mom,Dad):
def feature(self):
super().feature()
print("I am the Kid")
obk = Kid()
obk.feature()
print(Kid.mro())
print(Kid.__mro__)
Output:
I am your mom I am the Kid [<class '__main__.Kid'>, <class '__main__.Mom'>, <class '__main__.Dad'>, <class 'object'>] (<class '__main__.Kid'>, <class '__main__.Mom'>, <class '__main__.Dad'>, <class 'object'>)
The MRO order is Kid ---->Mom---->Dad---->object class for the class Kid.
Note: MRO always ensures the appearance of a child class before its parents.
Hybrid inheritance is a kind of inheritance in python that combines one or more forms of inheritance, for instance, a multilevel inheritance with multiple inheritances.so it can contain as many intermediate levels of classes in between superclass and child class. As the level rises so is the complexity too.
Here in our hybrid structure, Class D is created from the two derived classes B and C whose base class is A. This shows a blend of multilevel and multiple inheritances.
Observe the below example:
class Shape:
def __init__(self,name,length,breadth):
self.name=name
self.l=length
self.b=breadth
def display(self):
print("Length is :",self.l)
print("Breadth is :",self.b)
class Rect(Shape):
def R_area(self):
a=self.l*self.b
print("Area of",self.name,"is",a)
class Square(Shape):
def peri(self):
p =4*self.l
print("Perimeter of square is",p)
class Quad(Rect, Square):
def prt(self):
print('Rectangle and Square are quadrilaterals')
obq = Quad('Rectangle',10,20)
obq.display()
obq.R_area()
obq.peri()
obq.prt()
print(Quad.mro())
Output:
Length is : 10 Breadth is : 20 Area of Rectangle is 200 Perimeter of square is 40 Rectangle and Square are quadrilaterals [<class '__main__.Quad'>, <class '__main__.Rect'>, <class '__main__.Square'>, <class '__main__.Shape'>, <class 'object'>]
The MRO order of class quad is Quad---->Rect---->Square---->Shape---->Object.
Python offers two built-in inheritance methods to check the inheritance approach. They are :
isinstance( object, type)
issubclass( object, class)
For our previous example let’s check how the built-in methods check the inheritance in python.
x = isinstance(obq, Quad)
print(x)
x = issubclass(Rect,Shape)
print(x)
Output:
True True