Photo by Amélie Mourichon on Unsplash
Encapsulation, Abstraction, Inheritance, and Polymorphism are the basic pillars of Object-Oriented Programming. In this article, I will be taking you through these concepts and how those are implemented in Python.
Before explaining these concepts we should know some basics, those are:
- Class:
It is the way to define the user defined object type. It has set of methods and attributes which are applicable to similar kind of objects.
- Object
It is instantiation of class, which carry forwards all the characteristics of class.
- Methods
Methods are nothing but the functions which perform some activity in class for the particular object.
I would like to explain these basics through an example, below example depicts Employee class, where headquarter is class variable and init method acts as constructor here, init method is called whenever there is new object creation.
Class variable is common to all the objects, that is each object will have same class variable value, and also we can access this with the help of class name as shown in below example:
# Class for Employee
class Employee:
# Class Variable
headquarter = "Mumbai"
# The init method or constructor
def __init__(self, empid):
# Instance Variable
self.empid = empid
def display(self):
print("Employee has employee id",self.empid)
# Instantiation of class
a = Employee(10001) #a is object of class Employee
b = Employee(10002) #b is object of class Employee
print(a.headquarter) # prints "Mumbai"
print(b.headquarter) # prints "Mumbai"
a.display() # To access the method of class
print(b.empid) # To access the attributes of object
# Class attributes can be accessed using class name as well
print(Employee.headquarter) # prints "Mumbai"
Encapsulation in Python
Encapsulation is nothing but preventing the access of data. To protect the accidental changes in variables we need to have access restrictions on data. There are three types of access.
Public : read and write access to all
Protected : read and write access to the owner class and derived class
Private : read and write access to the owner class
Below example explains the access types, and how to access public, protected and private variables and methods.
If you see, salary is private variable and can be accessed only inside class, if you try to access through object you will get "AttributeError". Protected variables can be accessed using object as shown in below example, but to access the private variables/methods we need to use special syntax
<obj>._<class name>__<private variable/method>
class Employee:
__salary = 900000 # private variable
def __init__(self,name):
self.name = name # public variable
_department = "sales" #protected variable
def call_employee(self): # public method
print( "Calling",self.name)
def __bonus(self): # private method
self.__salary += 80000
print( "Total salary with bonus: ", self.__salary )
emp = Employee("Gayu") #object instantiation
print("Salary is",emp._Employee__salary) #accessing private variable
emp._Employee__bonus() #accessing private method
emp._department = "Marketing" #accessing protected variable
print( "New department is",emp._department )
print("Name of employee is",emp.name) #accessing public variable
emp.call_employee() #accessing public method
Output:
Salary is 900000
Total salary with bonus: 980000
New department is Marketing
Name of employee is Gayu
Calling Gayu
Inheritance in Python
There are five types of inheritance:
Single inheritance : single parent class for single child class
Multilevel inheritance : parent->child->grandchild relationship
Hierarchical inheritance : single parent class and multiple child class
Multiple inheritance : multiple parent class for one child class
Hybrid inheritance : combines more than one form of inheritance
Below example shows the single inheritance. Here Person is base class and Employee is derived class from it. If you miss to call the base class init method in child class then you won't be able to access the fname and lname parameters in any method of the child class.
#parent class
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname
def info(self):
print(self.firstname, self.lastname)
#child class
class Employee(Person):
def __init__(self, fname, lname, company):
super().__init__(fname, lname) #calling base class constructor
self.company = company
#method overriding
def info(self):
print("company for "+self.firstname, self.lastname +" is "+self.company")
x = Person("gayatri", "kale")
x.info()
y = Employee("andy", "beifong", "randomcompany")
y.info()
Output:
gayatri kale
company for andy beifong is randomcompany
The syntax while applying all other inheritance is similar to above example, only in case of multiple inheritance syntax would be :
class Base1:
pass
class Base2:
pass
class MultiDerived(Base1, Base2):
pass
Note: In case of inheritance if you don't want to provide the access of some variables to the base class then you can make those variables private variables by appending double underscores as explained in earlier section.
Abstraction in Python
Abstraction is used to hide the implementation details. Just like vehicles, you know how to drive them but you don't know how they internally work. In similar way abstraction helps to reduce the complexity by exposing only relevant information. In Python, abstraction is implemented through class named 'ABC' from the 'abc' module. A method becomes abstract when decorated with the keyword @abstractmethod.
Abstract methods does not have any implementation details in parent class. Base class having the abstract method cannot be instantiated.
Note : All the child classes inherited from parent class having abstract method should contain the abstract method or else we will get the error.
from abc import ABC, abstractmethod
class Game(ABC): #abstract class
@abstractmethod
def player_no(self): #abstract method
pass
class Football(Game):
players = 11
def player_no(self): #overriding abstract method
print("Total players in Football", self.players)
def points(self):
print("Touchdown, Field Goal, Safety, Two point conversion, Extra point ")
class Baseball(Game):
players = 9
def player_no(self): #overriding abstract method
print("Total players in Baseball", self.players)
foo = Football() #object created for the class 'Football'
ba = Baseball() #object created for the class 'Baseball
foo.player_no()
ba.player_no()
foo.points()
Output:
Total players in Football 11
Total players in Baseball 9
Touchdown, Field Goal, Safety, Two point conversion, Extra point
Polymorphism in Python
In layman's terms we can say 'same name with different functionality'. Below example explains the polymorphism. area() function executes differently for different type of objects. Method overriding which we have done in inheritance earlier that is also considered as example of polymorphism.
class Square:
def __init__(self,side):
self.side = side
def area(self): #polymorphism implementation
print("area of square: ",self.side*self.side)
class Rectangle:
def __init__(self,length,breadth):
self.length = length
self.breadth = breadth
def area(self): #polymorphism implementation
print("area of square: ",self.length*self.breadth)
sq = Square(4)
rec = Rectangle(3,4)
sq.area()
rec.area()
Output:
area of square: 16
area of square: 12
That's all I have for this article. Do follow the series if you want to explore more important concepts for Python Developer Interview.