Polymorphism
Poly
-> Many
Morphs
-> Forms
One name but multiple forms
Definition:
·
Polymorphism in Python's
object-oriented programming is the ability of an object to take on many
forms.
·
Specifically, it refers to the idea
that different objects can be treated as if they are the same type of object,
even if they are fundamentally different.
·
This concept of polymorphism can make
our code more flexible and easier to work with, as we don't need to write
separate functions for every different type of object we want to work with.
Example
For
example, let's say we have two classes: Dog and Cat. Both classes
have a method called speak(), but they behave differently. When we call speak()
on a Dog object, it will bark, while calling speak() on a Cat
object will make it meow.
Types of Polymorphism supported by Python
Duck
Typing Polymorphism: This is a form of dynamic typing in
which the type of an object is determined by its behavior or attributes rather
than by its explicit type. This means that any object can be used as a
parameter for a function as long as it has the necessary attributes or methods.
For example, if an object has a "quack" method, it can be treated as
a duck and passed as an argument to a function that expects a duck. Duck Typing
can be a powerful tool for writing flexible, reusable code, but it can also be
risky if you rely too much on object behavior without checking the object's
type first.
Operator
Overloading Polymorphism: Python allows you to overload
operators such as +, -, *, and /, allowing you to use them with custom objects.
For example, if you define the add() method in a class, you can use the +
operator with objects of that class.
Function
Overloading Polymorphism: Python does not support function
overloading in the traditional sense, where you can have multiple functions
with the same name but different parameters. However, you can achieve similar
functionality by using default values for parameters or by using
variable-length arguments (*args and **kwargs).
Method
Overriding Polymorphism: This is a form of subtype
polymorphism in which a subclass provides its own implementation of a method
that is already defined in its parent class. When the method is called on an
object of the subclass, the subclass's implementation is used instead of the
parent class's implementation.
Abstract
Base Classes Polymorphism: Python's built-in abc module allows
you to define abstract base classes, which are classes that cannot be
instantiated but define a common interface for their subclasses. This allows
you to write code that operates on objects of different classes as long as they
inherit from the same abstract base class.
Operator Overloading
Operator
overloading is a feature in Python that allows you to define how operators such
as +, -, *, /, ==, !=, <, >, <=, and >= behave with custom objects.
In
Python, operators such as +, -, *, /, ==, !=, <, >, <=, and >= can
be used with built-in data types like integers and strings. However, it's also
possible to overload these operators for custom objects by defining special
methods known as "magic" or "dunder" methods. These
methods have double underscores (__) before and after their names, such as
add() for the + operator.
Operator |
Magic Method |
Description |
Addition (+) |
__add__(self, other) |
Adds two objects |
Subtraction (-) |
__sub__(self, other) |
Subtracts two objects |
Multiplication (*) |
__mul__(self, other) |
Multiplies two objects |
Division (/) |
__truediv__(self, other) |
Divides two objects |
Floor Division (//) |
__floordiv__(self, other) |
Performs floor division on two objects |
Modulus (%) |
__mod__(self, other) |
Computes the remainder of two objects |
Exponentiation (**) |
__pow__(self, other) |
Raises one object to the power of another object |
Negation (-) |
__neg__(self) |
Returns the negative of an object |
Absolute Value (abs()) |
__abs__(self) |
Returns the absolute value of an object |
Equality (==) |
__eq__(self, other) |
Tests for equality between two objects |
Inequality (!=) |
__ne__(self, other) |
Tests for inequality between two objects |
Less Than (<) |
__lt__(self, other) |
Tests if one object is less than another object |
Greater Than (>) |
__gt__(self, other) |
Tests if one object is greater than another object |
Less Than or Equal To (<=) |
__le__(self, other) |
Tests if one object is less than or equal to another object |
Greater Than or Equal To (>=) |
__ge__(self, other) |
Tests if one object is greater than or equal to another object |
|
|
|
Boolean (bool()) |
__bool__(self) |
Converts an object to a Boolean value |
Common shorthand operator overloading magic
methods in Python:
Operator |
Magic Method |
Description |
Addition Assignment (+=) |
__iadd__(self, other) |
Adds two objects and assigns the result to the first object |
Subtraction Assignment (-=) |
__isub__(self, other) |
Subtracts two objects and assigns the result to the first object |
Multiplication Assignment (*=) |
__imul__(self, other) |
Multiplies two objects and assigns the result to the first object |
Division Assignment (/=) |
__itruediv__(self, other) |
Divides two objects and assigns the result to the first object |
Floor Division Assignment (//=) |
__ifloordiv__(self, other) |
Performs floor division on two objects and assigns the result to the
first object |
Modulus Assignment (%=) |
__imod__(self, other) |
Computes the remainder of two objects and assigns the result to the
first object |
Exponentiation Assignment (**=) |
__ipow__(self, other[, modulo]) |
Raises one object to the power of another object and assigns the
result to the first object |
Bitwise NOT (~) |
__invert__(self) |
Performs a bitwise NOT operation on an object |
Example Program:
#Operator
Overloading
class
Person:
def __init__(self,amount):
self.amount = amount
def __add__(self,other):
return self.amount + other.amount
def __sub__(self,other):
return self.amount - other.amount
p1
= Person(100)
p2
= Person(50)
print("p1
+ p2 = " , p1+p2)
print("p1
- p2 = " , p1-p2)
Output:
p1
+ p2 = 150
p1
- p2 = 50
Program 2:
#Operator Overloading with more than 2 objects
class Person:
def __init__(self,amount):
self.amount = amount
def __add__(self,other):
total = self.amount + other.amount
return Person(total)
def __str__(self):
return f"The Result is {self.amount}"
p1 = Person(500)
p2 = Person(50)
p3 = Person(200)
print(p1+p2+p3)
The Output is:
The Result is 750
Note:
- Whenever we are calling + operator, then __add__() method will be called.
- +operator return type will become __add__() method return type
- Whenever we are printing Person Object Reference, then __str__() method will be called.
- If we not providing this method(__str__()), then default implementation will be executed
Important
Points to note when using operator overloading.
1.
The operator should be defined within
the class: Operator overloading only works with class types, so the overloaded
operator should be defined as a member function or a friend function of the
class.
2.
The operator should be overloaded for
a specific purpose: Overloading operators should be done for a specific
purpose, such as performing mathematical operations or comparing objects.
3.
The overloaded operator's behavior
should be consistent with its traditional use: When overloading an operator,
it's important to ensure that the behavior of the operator is consistent with
its traditional use. For example, the "+" operator should perform
addition, not subtraction.
4.
The operator should return a new
object: When an operator is overloaded, it should return a new object rather
than modifying the operands.
5.
The operator should be implemented
efficiently: When overloading an operator, it's important to ensure that the
implementation is efficient, as operator overloading can be slower than regular
function calls.
6.
The behavior of the overloaded
operator should be well-documented: It's important to document the behavior of
the overloaded operator to ensure that other developers can understand the
intended behavior and use the operator correctly.
7.
Overloading should be used
judiciously: Overloading too many operators can make code difficult to read and
maintain, so overloading should be used judiciously. It's important to ensure
that the overloaded operator adds clarity and simplicity to the code rather
than making it more complex.
Self
Assessment Questions:
1.
What is operator overloading in
Python?
2.
Which dunder method is used to
overload the "+" operator?
3.
What is the purpose of the
"str" dunder method?
4.
Can the "in" operator be
overloaded in Python?
5.
What is the difference between
"eq" and "ne" dunder methods?
6.
How can you overload the
">" operator in Python?
7.
Is it possible to overload the
"is" operator in Python? Why or why not?
8.
What is the "call" dunder
method used for in Python?
9.
How can you overload the
"[]" operator in Python?
10.
What is the difference between
"lt" and "le" dunder methods?
Programming
Exercises:
1.
Write a Python class called
"Rectangle" that represents a rectangle with length and width
dimensions. Overload the "+" operator to allow two Rectangle objects
to be added together to create a new Rectangle with the combined dimensions.
Overload the "==" operator to allow two Rectangle objects to be
compared for equality based on their dimensions. Implement a method called
"area" that returns the area of the rectangle.
2.
Create a class called Time that has
separate int member data for hours, minutes and seconds. One constructor should
initialize this data to 0. and another should initialize it to fixed values. A
member function should display it, in 11:59:59 format. Write a program to add
time of two objects by overloading '+' operator.
3.
Create a class whose object represents
a complex number (A complex number contains a real part and an imaginary part).
Write a program so that it is possible to add two objects of this class and
store the result in third object.
4.
Write a Python class called
"EmailAddress" that represents an email address. Overload the
"==" operator to allow two EmailAddress objects to be compared for
equality based on their email address strings. Overload the "+" operator
to allow two EmailAddress objects to be concatenated together to create a new
EmailAddress object with a combined email address.
5.
Create a Python program that extends
the functionality (overloading) of the + operator to handle the addition of two
different data types, such as strings and numbers.
Comments
Post a Comment