0% found this document useful (0 votes)
166 views

Polymorphism and Inheritance in Python

The document discusses polymorphism in Python, including how it allows objects to take different forms and how methods can process objects differently depending on their class or data type. It provides examples of polymorphism using built-in functions like len(), method overriding with inheritance, and overloading built-in methods.

Uploaded by

Swati Patel
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
166 views

Polymorphism and Inheritance in Python

The document discusses polymorphism in Python, including how it allows objects to take different forms and how methods can process objects differently depending on their class or data type. It provides examples of polymorphism using built-in functions like len(), method overriding with inheritance, and overloading built-in methods.

Uploaded by

Swati Patel
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 23

Polymorphism in Python

Object-Oriented Programming (OOP) has four essential characteristics: abstraction,


encapsulation, inheritance, and polymorphism.

This lesson will cover what polymorphism is and how to implement them in Python. Also,
you’ll learn how to implement polymorphism using function overloading, method
overriding, and operator overloading.

What is Polymorphism in Python?


Polymorphism in Python is the ability of an object to take many forms. In simple words,
polymorphism allows us to perform the same action in many different ways.

For example, Jessa acts as an employee when she is at the office. However, when she is at
home, she acts like a wife. Also, she represents herself differently in different places.
Therefore, the same person takes different forms as per the situation.

In polymorphism, a method can process objects differently depending on the class type


or data type. Let’s see simple examples to understand it better.

Polymorphism in Built-in function len()

The built-in function len() calculates the length of an object depending upon its type. If an
object is a string, it returns the count of characters, and If an object is a list, it returns the
count of items in a list.

The len() method treats an object as per its class type.

Example:

students = ['Emma', 'Jessa', 'Kelly']


school = 'ABC School'

# calculate count
print(len(students))
print(len(school))

Output

10
Polymorphic
len() function

Polymorphism With Inheritance


Polymorphism is mainly used with inheritance. In inheritance, child class inherits the
attributes and methods of a parent class. The existing class is called a base class or parent
class, and the new class is called a subclass or child class or derived class.

Using method overriding polymorphism allows us to defines methods in the


child class that have the same name as the methods in the parent class. This process of re-
implementing the inherited method in the child class is known as Method Overriding.

Advantage of method overriding

 It is effective when we want to extend the functionality by altering the inherited


method. Or the method inherited from the parent class doesn’t fulfill the need of a
child class, so we need to re-implement the same method in the child class in a
different way.
 Method overriding is useful when a parent class has multiple child classes, and one of
that child class wants to redefine the method. The other child classes can use the
parent class method. Due to this, we don’t need to modification the parent class code
In polymorphism, Python first checks the object’s class type and executes the
appropriate method when we call the method. For example, If you create the Car object,
then Python calls the speed() method from a Car class.
Let’s see how it works with the help of an example.

Example: Method Overriding

In this example, we have a vehicle class as a parent and a ‘Car’ and ‘Truck’ as its sub-class.
But each vehicle can have a different seating capacity, speed, etc., so we can have the
same instance method name in each class but with a different implementation. Using this
code can be extended and easily maintained over time.

Polymorphis
m with Inheritance

class Vehicle:

def __init__(self, name, color, price):


self.name = name
self.color = color
self.price = price

def show(self):
print('Details:', self.name, self.color, self.price)

def max_speed(self):
print('Vehicle max speed is 150')

def change_gear(self):
print('Vehicle change 6 gear')

# inherit from vehicle class


class Car(Vehicle):
def max_speed(self):
print('Car max speed is 240')

def change_gear(self):
print('Car change 7 gear')

# Car Object
car = Car('Car x1', 'Red', 20000)
car.show()
# calls methods from Car class
car.max_speed()
car.change_gear()

# Vehicle Object
vehicle = Vehicle('Truck x1', 'white', 75000)
vehicle.show()
# calls method from a Vehicle class
vehicle.max_speed()
vehicle.change_gear()

Output:

Details: Car x1 Red 20000

Car max speed is 240

Car change 7 gear

Details: Truck x1 white 75000

Vehicle max speed is 150

Vehicle change 6 gear

As you can see, due to polymorphism, the Python interpreter recognizes that
the max_speed() and change_gear() methods are overridden for the car object. So, it uses the
one defined in the child class (Car)

On the other hand, the show() method isn’t overridden in the Car class, so it is used from
the Vehicle class.

Overrride Built-in Functions

In Python, we can change the default behavior of the built-in functions. For example, we
can change or extend the built-in functions such as len(), abs(), or divmod() by redefining
them in our class. Let’s see the example.

Example

In this example, we will redefine the function len()


class Shopping:
def __init__(self, basket, buyer):
self.basket = list(basket)
self.buyer = buyer

def __len__(self):
print('Redefine length')
count = len(self.basket)
# count total items in a different way
# pair of shoes and shir+pant
return count * 2

shopping = Shopping(['Shoes', 'dress'], 'Jessa')


print(len(shopping))

Output

Redefine length

Polymorphism In Class methods


Polymorphism with class methods is useful when we group different objects having the
same method. we can add them to a list or a tuple, and we don’t need to check the object
type before calling their methods. Instead, Python will check object type at runtime and call
the correct method. Thus, we can call the methods without being concerned about which
class type each object is. We assume that these methods exist in each class.

Python allows different classes to have methods with the same name.

 Let’s design a different class in the same way by adding the same methods in two or
more classes.
 Next, create an object of each class
 Next, add all objects in a tuple.
 In the end, iterate the tuple using a for loop and call methods of a object without
checking its class.
Example

In the below example, fuel_type() and max_speed() are the instance methods created in both


classes.

class Ferrari:
def fuel_type(self):
print("Petrol")
def max_speed(self):
print("Max speed 350")

class BMW:
def fuel_type(self):
print("Diesel")

def max_speed(self):
print("Max speed is 240")

ferrari = Ferrari()
bmw = BMW()

# iterate objects of same type


for car in (ferrari, bmw):
# call methods without checking class of object
car.fuel_type()
car.max_speed()

Output

Petrol

Max speed 350

Diesel

Max speed is 240

As you can see, we have created two classes Ferrari and BMW. They have the same instance
method names fuel_type() and max_speed(). However, we have not linked both the classes
nor have we used inheritance.

We packed two different objects into a tuple and iterate through it using a car variable. It is
possible due to polymorphism because we have added the same method in both classes
Python first checks the object’s class type and executes the method present in its class.

Polymorphism with Function and Objects

We can create polymorphism with a function that can take any object as a parameter and
execute its method without checking its class type. Using this, we can call object actions
using the same function instead of repeating method calls.

Example

class Ferrari:
def fuel_type(self):
print("Petrol")

def max_speed(self):
print("Max speed 350")

class BMW:
def fuel_type(self):
print("Diesel")

def max_speed(self):
print("Max speed is 240")

# normal function
def car_details(obj):
obj.fuel_type()
obj.max_speed()

ferrari = Ferrari()
bmw = BMW()

car_details(ferrari)
car_details(bmw)

Output

Petrol

Max speed 350

Diesel

Max speed is 240

Polymorphism In Built-in Methods


The word polymorphism is taken from the Greek words poly (many) and morphism (forms).
It means a method can process objects differently depending on the class type or data
type.

The built-in function reversed(obj) returns the iterable by reversing the given object. For
example, if you pass a string to it, it will reverse it. But if you pass a list of strings to it, it will
return the iterable by reversing the order of elements (it will not reverse the individual
string).

Let us see how a built-in method process objects having different data types.

Example:

students = ['Emma', 'Jessa', 'Kelly']


school = 'ABC School'

print('Reverse string')
for i in reversed('PYnative'):
print(i, end=' ')

print('\nReverse list')
for i in reversed(['Emma', 'Jessa', 'Kelly']):
print(i, end=' ')

Output:

Reverse string

e v i t a n Y P

Reverse list

Kelly Jessa Emma

Method Overloading
The process of calling the same method with different parameters is known as method
overloading. Python does not support method overloading. Python considers only the
latest defined method even if you overload the method. Python will raise a TypeError if you
overload the method.

Example

def addition(a, b):


c = a + b
print(c)

def addition(a, b, c):


d = a + b + c
print(d)

# the below line shows an error


# addition(4, 5)

# This line will call the second product method


addition(3, 7, 5)

 Run
To overcome the above problem, we can use different ways to achieve the method
overloading. In Python, to overload the class method, we need to write the method’s logic
so that different code executes inside the function depending on the parameter passes.
For example, the built-in function range() takes three parameters and produce different
result depending upon the number of parameters passed to it.

Example:

for i in range(5): print(i, end=', ')


print()
for i in range(5, 10): print(i, end=', ')
print()
for i in range(2, 12, 2): print(i, end=', ')

 Run
Output:

0, 1, 2, 3, 4,

5, 6, 7, 8, 9,

2, 4, 6, 8, 10,

Let’s assume we have an area() method to calculate the area of a square and rectangle. The
method will calculate the area depending upon the number of parameters passed to it.

 If one parameter is passed, then the area of a square is calculated


 If two parameters are passed, then the area of a rectangle is calculated.
Example: User-defined polymorphic method

class Shape:
# function with two default parameters
def area(self, a, b=0):
if b > 0:
print('Area of Rectangle is:', a * b)
else:
print('Area of Square is:', a ** 2)

square = Shape()
square.area(5)

rectangle = Shape()
rectangle.area(5, 3)

Output:

Area of Square is: 25

Area of Rectangle is: 15


Operator Overloading in Python
Operator overloading means changing the default behavior of an operator depending on
the operands (values) that we use. In other words, we can use the same operator for
multiple purposes.

For example, the + operator will perform an arithmetic addition operation when used with
numbers. Likewise, it will perform concatenation when used with strings.

The operator + is used to carry out different operations for distinct data types. This is one
of the most simple occurrences of polymorphism in Python.

Example:

# add 2 numbers
print(100 + 200)

# concatenate two strings


print('Jess' + 'Roy')

# merger two list


print([10, 20, 30] + ['jessa', 'emma', 'kelly'])

Output:

300

JessRoy

[10, 20, 30, 'jessa', 'emma', 'kelly']

Overloading + operator for custom objects

Suppose we have two objects, and we want to add these two objects with a
binary + operator. However, it will throw an error if we perform addition because the
compiler doesn’t add two objects. See the following example for more details.

Example:

class Book:
def __init__(self, pages):
self.pages = pages

# creating two objects


b1 = Book(400)
b2 = Book(300)
# add two objects
print(b1 + b2)

Output

TypeError: unsupported operand type(s) for +: 'Book' and 'Book'

We can overload + operator to work with custom objects also. Python provides some
special or magic function that is automatically invoked when associated with that particular
operator.

For example, when we use the + operator, the magic method __add__() is automatically


invoked. Internally + operator is implemented by using __add__() method. We have to
override this method in our class if you want to add two custom objects.

Example:

class Book:
def __init__(self, pages):
self.pages = pages

# Overloading + operator with magic method


def __add__(self, other):
return self.pages + other.pages

b1 = Book(400)
b2 = Book(300)
print("Total number of pages: ", b1 + b2)

Output

Total number of pages: 700

Overloading the * Operator

The * operator is used to perform the multiplication. Let’s see how to overload it to


calculate the salary of an employee for a specific period. Internally * operator is
implemented by using the __mul__() method.

Example:

class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary

def __mul__(self, timesheet):


print('Worked for', timesheet.days, 'days')
# calculate salary
return self.salary * timesheet.days

class TimeSheet:
def __init__(self, name, days):
self.name = name
self.days = days

emp = Employee("Jessa", 800)


timesheet = TimeSheet("Jessa", 50)
print("salary is: ", emp * timesheet)

Output

Wroked for 50 days

salary is: 40000

Magic Methods: In Python, there are different magic methods available to perform
overloading operations. The below table shows the magic methods names to overload the
mathematical operator, assignment operator, and relational operators in Python.

Operator Name Symbol Magic method

Addition + __add__(self, other)

Subtraction - __sub__(self, other)

Multiplication * __mul__(self, other)

Division / __div__(self, other)

Floor Division // __floordiv__(self,other)

Modulus % __mod__(self, other)

Power ** __pow__(self, other)

Increment += __iadd__(self, other)

Decrement -= __isub__(self, other)

Product *= __imul__(self, other)


Operator Name Symbol Magic method

Division /+ __idiv__(self, other)

Modulus %= __imod__(self, other)

Power **= __ipow__(self, other)

Less than < __lt__(self, other)

Greater than > __gt__(self, other)

Less than or equal to <= __le__(self, other)

Greater than or equal to >= __ge__(self, other)

Equal to == __eq__(self, other)

Not equal != __ne__(self, other)

magic methods

Inheritance in Python
The process of inheriting the properties of the parent class into a child class is called inheritance. The
existing class is called a base class or parent class and the new class is called a subclass or child class or
derived class.

In this Python lesson, you will learn inheritance, method overloading, method overriding, types of
inheritance, and MRO (Method Resolution Order). In Object-oriented programming, inheritance is an
important aspect. The main purpose of inheritance is the reusability of code because we can use the
existing class to create a new class instead of creating it from scratch.

In inheritance, the child class acquires all the data members, properties, and functions from the parent class.
Also, a child class can also provide its specific implementation to the methods of the parent class.

For example, In the real world, Car is a sub-class of a Vehicle class. We can create a Car by inheriting the
properties of a Vehicle such as Wheels, Colors, Fuel tank, engine, and add extra properties in Car as
required.

Syntax

class BaseClass:
Body of base class
class DerivedClass(BaseClass):
Body of derived class
Types Of Inheritance: In Python, based upon the number of child and parent
classes involved, there are five types of inheritance. The type of inheritance are listed below:

1. Single inheritance
2. Multiple Inheritance
3. Multilevel inheritance
4. Hierarchical Inheritance
5. Hybrid Inheritance

Single Inheritance
In single inheritance, a child class inherits from a single-parent class. Here is one child class and one parent
class.

Python Single Inheritance


Example

Let’s create one parent class called ClassOne and one child class called ClassTwo to implement single
inheritance.

# Base class
class Vehicle:
def Vehicle_info(self):
print('Inside Vehicle class')

# Child class
class Car(Vehicle):
def car_info(self):
print('Inside Car class')

# Create object of Car


car = Car()

# access Vehicle's info using car object


car.Vehicle_info()
car.car_info()

Output

Inside Vehicle class

Inside Car class


Multiple Inheritance: In multiple inheritance, one child class can inherit from
multiple parent classes. So here is one child class and multiple parent classes.

Python Multiple Inheritance


Example

# Parent class 1
class Person:
def person_info(self, name, age):
print('Inside Person class')
print('Name:', name, 'Age:', age)

# Parent class 2
class Company:
def company_info(self, company_name, location):
print('Inside Company class')
print('Name:', company_name, 'location:', location)

# Child class
class Employee(Person, Company):
def Employee_info(self, salary, skill):
print('Inside Employee class')
print('Salary:', salary, 'Skill:', skill)

# Create object of Employee


emp = Employee()

# access data
emp.person_info('Jessa', 28)
emp.company_info('Google', 'Atlanta')
emp.Employee_info(12000, 'Machine Learning')

Output

Inside Person class

Name: Jessa Age: 28

Inside Company class

Name: Google location: Atlanta

Inside Employee class

Salary: 12000 Skill: Machine Learning


In the above example, we created two parent classes Person and Company respectively. Then we create one
child called Employee which inherit from Person and Company classes.

Multilevel inheritance
In multilevel inheritance, a class inherits from a child class or derived class. Suppose three classes A, B, C.
A is the superclass, B is the child class of A, C is the child class of B. In other words, we can say a chain of
classes is called multilevel inheritance.

Example

# Base class
class Vehicle:
def Vehicle_info(self):
print('Inside Vehicle class')

# Child class
class Car(Vehicle):
def car_info(self):
print('Inside Car class')

# Child class
class SportsCar(Car):
def sports_car_info(self):
print('Inside SportsCar class')

# Create object of SportsCar


s_car = SportsCar()

# access Vehicle's and Car info using SportsCar object


s_car.Vehicle_info()
s_car.car_info()
s_car.sports_car_info()

Output

Inside Vehicle class

Inside Car class

Inside SportsCar class

In the above example, we can see there are three classes named Vehicle, Car, SportsCar. Vehicle is the
superclass, Car is a child of Vehicle, SportsCar is a child of Car. So we can see the chaining of classes.

Hierarchical Inheritance
In Hierarchical inheritance, more than one child class is derived from a single parent class. In other words,
we can say one parent class and multiple child classes.
Python hierarchical inheritance

Example

Let’s create ‘Vehicle’ as a parent class and two child class ‘Car’ and ‘Truck’ as a parent class.

class Vehicle:
def info(self):
print("This is Vehicle")

class Car(Vehicle):
def car_info(self, name):
print("Car name is:", name)

class Truck(Vehicle):
def truck_info(self, name):
print("Truck name is:", name)

obj1 = Car()
obj1.info()
obj1.car_info('BMW')

obj2 = Truck()
obj2.info()
obj2.truck_info('Ford')

Output

This is Vehicle

Car name is: BMW

This is Vehicle

Truck name is: Ford

Hybrid Inheritance
When inheritance is consists of multiple types or a combination of different inheritance is called hybrid
inheritance.

Example
class Vehicle:
def vehicle_info(self):
print("Inside Vehicle class")

class Car(Vehicle):
def car_info(self):
print("Inside Car class")

class Truck(Vehicle):
def truck_info(self):
print("Inside Truck class")

# Sports Car can inherits properties of Vehicle and Car


class SportsCar(Car, Vehicle):
def sports_car_info(self):
print("Inside SportsCar class")

# create object
s_car = SportsCar()

s_car.vehicle_info()
s_car.car_info()
s_car.sports_car_info()

Note: In the above example, hierarchical and multiple inheritance exists. Here we created, parent


class Vehicle and two child classes named Car and Truck this is hierarchical inheritance.

Another is SportsCar inherit from two parent classes named Car and Vehicle. This is multiple inheritance.

Python super() function
When a class inherits all properties and behavior from the parent class is called inheritance. In such a case,
the inherited class is a subclass and the latter class is the parent class.

In child class, we can refer to parent class by using the super() function. The super function returns a
temporary object of the parent class that allows us to call a parent class method inside a child class method.

Benefits of using the super() function.

1. We are not required to remember or specify the parent class name to access its methods.
2. We can use the super() function in both single and multiple inheritances.
3. The super() function support code reusability as there is no need to write the entire function

Example

class Company:
def company_name(self):
return 'Google'

class Employee(Company):
def info(self):
# Calling the superclass method using super()function
c_name = super().company_name()
print("Jessa works at", c_name)
# Creating object of child class
emp = Employee()
emp.info()

Output:

Jessa works at Google

In the above example, we create a parent class Company and child class Employee. In Employee class, we call
the parent class method by using a super() function.

issubclass() 
In Python, we can verify whether a particular class is a subclass of another class. For this purpose, we can
use Python built-in function issubclass(). This function returns True if the given class is the subclass of the
specified class. Otherwise, it returns False.

Syntax

issubclass(class, classinfo)

Where,

 class: class to be checked.


 classinfo: a class, type, or a tuple of classes or data types.
Example

class Company:
def fun1(self):
print("Inside parent class")

class Employee(Company):
def fun2(self):
print("Inside child class.")

class Player:
def fun3(self):
print("Inside Player class.")

# Result True
print(issubclass(Employee, Company))

# Result False
print(issubclass(Employee, list))

# Result False
print(issubclass(Player, Company))

# Result True
print(issubclass(Employee, (list, Company)))
# Result True
print(issubclass(Company, (list, Company)))

Also, see Python isinstance().

Method Overriding
In inheritance, all members available in the parent class are by default available in the child class. If the
child class does not satisfy with parent class implementation, then the child class is allowed to redefine that
method by extending additional functions in the child class. This concept is called method overriding.

When a child class method has the same name, same parameters, and same return type as a method in its
superclass, then the method in the child is said to override the method in the parent class.

Example

class Vehicle:
def max_speed(self):
print("max speed is 100 Km/Hour")

class Car(Vehicle):
# overridden the implementation of Vehicle class
def max_speed(self):
print("max speed is 200 Km/Hour")

# Creating object of Car class


car = Car()
car.max_speed()

Output:

max speed is 200 Km/Hour

In the above example, we create two classes named Vehicle (Parent class) and Car (Child class). The class
Car extends from the class Vehicle so, all properties of the parent class are available in the child class. In
addition to that, the child class redefined the method max_speed().

Method Resolution Order in Python


In Python, Method Resolution Order(MRO) is the order by which Python looks for a method or attribute.
First, the method or attribute is searched within a class, and then it follows the order we specified while
inheriting.

This order is also called the Linearization of a class, and a set of rules is called MRO (Method Resolution
Order). The MRO plays an essential role in multiple inheritances as a single method may found in
multiple parent classes.

In multiple inheritance, the following search order is followed.


1. First, it searches in the current parent class if not available, then searches in the parents class specified
while inheriting (that is left to right.)
2. We can get the MRO of a class. For this purpose, we can use either the mro attribute or
the mro() method.

Example

class A:

def process(self):

print(" In class A")

class B(A):

def process(self):

print(" In class B")

class C(B, A):

def process(self):

print(" In class C")

# Creating object of C class

C1 = C()

C1.process()

print(C.mro())

# In class C

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

In the above example, we create three classes named A, B and C. Class B is inherited from A, class C inherits
from B and A. When we create an object of the C class and calling the process() method, Python looks for
the process() method in the current class in the C class itself.

Then search for parent classes, namely B and A, because C class inherit from B and A. that is, C(B, A) and
always search in left to right manner.

Abstraction classes in Python


In Python, abstraction can be achieved by using abstract classes and interfaces.

A class that consists of one or more abstract method is called the abstract class. Abstract methods
do not contain their implementation. Abstract class can be inherited by the subclass and abstract
method gets its definition in the subclass. Abstraction classes are meant to be the blueprint of the
other class. An abstract class can be useful when we are designing large functions. An abstract
class is also helpful to provide the standard interface for different implementations of components.
Python provides the abc module to use the abstraction in the Python program. Let's see the
following syntax.

Syntax

1. from abc import ABC  
2. class ClassName(ABC):  

We import the ABC class from the abc module.

Abstract Base Classes


An abstract base class is the common application program of the interface for a set of subclasses.
It can be used by the third-party, which will provide the implementations such as with plugins. It is
also beneficial when we work with the large code-base hard to remember all the classes.

Working of the Abstract Classes


Unlike the other high-level language, Python doesn't provide the abstract class itself. We need to
import the abc module, which provides the base for defining Abstract Base classes (ABC). The ABC
works by decorating methods of the base class as abstract. It registers concrete classes as the
implementation of the abstract base. We use the @abstractmethod decorator to define an
abstract method or if we don't provide the definition to the method, it automatically becomes the
abstract method. Let's understand the following example.

Example -

1. # Python program demonstrate  
2. # abstract base class work   
3. from abc import ABC, abstractmethod   
4. class Car(ABC):   
5.     def mileage(self):   
6.         pass  
7.   
8. class Tesla(Car):   
9.     def mileage(self):   
10.         print("The mileage is 30kmph")   
11. class Suzuki(Car):   
12.     def mileage(self):   
13.         print("The mileage is 25kmph ")   
14. class Duster(Car):   
15.      def mileage(self):   
16.           print("The mileage is 24kmph ")   
17.   
18. class Renault(Car):   
19.     def mileage(self):   
20.             print("The mileage is 27kmph ")   
21.           
22. # Driver code   
23. t= Tesla ()   
24. t.mileage()   
25.   
26. r = Renault()   
27. r.mileage()   
28.   
29. s = Suzuki()   
30. s.mileage()   
31. d = Duster()   
32. d.mileage()  

Output:

The mileage is 30kmph


The mileage is 27kmph
The mileage is 25kmph
The mileage is 24kmph

Explanation -

In the above code, we have imported the abc module to create the abstract base class. We
created the Car class that inherited the ABC class and defined an abstract method named
mileage(). We have then inherited the base class from the three different subclasses and
implemented the abstract method differently. We created the objects to call the abstract method.

Points to Remember
Below are the points which we should remember about the abstract base class in Python.

o An Abstract class can contain the both method normal and abstract method.
o An Abstract cannot be instantiated; we cannot create objects for the abstract class.

Abstraction is essential to hide the core functionality from the users. We have covered the all the
basic concepts of Abstraction in Python.

You might also like