Featured

    Featured Posts

Python OOPS Tutorial 9: Polymorphism In Python






Polymorphism with Function and Objects: -

 §  In Python we cannot specify the type explicitly. Based on provided value at runtime the type will be considered automatically. Hence Python is considered as Dynamically Typed Programming Language.



 §  You can create a function that can take any object, allowing for polymorphism.

def figure(obj):      
      obj.draw()

 §  What is the type of obj? We cannot decide at the beginning. At runtime we can pass any type. Then how we can decide the type?

 §  Let’s take an example and create a function called 'figure()' which will take an object which we will name 'obj'. Now, let’s give the function something to do that uses the 'obj' object we passed to it.

 §  In this case, let’s call the methods draw () and color (), each of which is defined in the three classes 'Circle' and 'Rectangle’, ‘Square'. Now, you have to create instantiations of these classes:


class Circle:
    def draw(self):
        print('Circle Shape Draw!.')
    def color(self):
        print('Yellow Color Fill In Circle!.')

class Rectangle:
    def draw(self):
        print('Rectangle Shape Draw!.')
    def color(self):
        print('Green Color Fill In Rectangle!.')

class Square:
    def draw(self):
        print('Square Shape Draw!.')
    def color(self):
        print('Pink Color Fill In Square!.')

#define function for Polymorphism 
def figure(obj):
    obj.draw() 
    obj.color()     
l=[Circle(),Rectangle(),Square()]
for obj in l:
    figure(obj)
    print('===========================')

output:
Circle Shape Draw!.
Yellow Color Fill In Circle!.
====================
Rectangle Shape Draw!.
Green Color Fill In Rectangle!.
====================
Square Shape Draw!.
Pink Color Fill In Square!.
====================
§  The problem in this approach is if obj does not contain draw() method then we will get AttributeError

class Circle:
    def draw(self):
        print('Circle Shape Draw!.')

class Rectangle:
    def paint(self):
        print('Rectangle Shape Paint!.')

class Square:
    def draw(self):
        print('Square Shape Draw!.')

class Triangle:
    def paint(self):
        print('Triangle Shape Paint!.')

#define function for Polymorphism 
def figure(obj):
    obj.draw()
     
l=[Circle(),Rectangle(),Square(),Triangle]
for obj in l:
    figure(obj)
   print('===========================')
output:
    Circle Shape Draw!.
===========================
  obj.draw() 
AttributeError: 'Rectangle' object has no attribute 'draw'

Demo Program with hasattr() function:
 §  The hasattr() method returns true if an object has the given named attribute and false if it does not.

The syntax of hasattr() method is:
hasattr(object, name)

The hasattr() method takes two parameters:
object - object whose named attribute is to be checked
name - name of the attribute to be searched.

 §  In The given figure there are four classes Circle,Rectangle,Square,Triangle where Circle, Square classes contain draw() method and Rectangle,Triangle classes contain paint() method.

class Circle:
    def draw(self):
        print('Circle Shape Draw!.')

class Rectangle:
    def paint(self):
        print('Rectangle Shape Paint!.')

class Square:
    def draw(self):
        print('Square Shape Draw!.')

class Triangle:
    def paint(self):
        print('Triangle Shape Paint!.')

#define function for Polymorphism 
def figure(obj):
    if hasattr(obj,'draw'):
        obj.draw()
    elif hasattr(obj,'paint'): 
        obj.paint()    

#Create a list which contain given class object     
l=[Circle(),Rectangle(),Square(),Triangle()]
for obj in l:
    figure(obj)
    print('===========================')   

output:
Circle Shape Draw!.
===========================
Rectangle Shape Paint!.
===========================
Square Shape Draw!.
===========================
Triangle Shape Paint!.
===========================

 
§  Polymorphism with Instance Methods


 
§  See the above, diagram in the given diagram there are three classes. All the classes have two methods. Now we will see how to call. Here, you have to create a for loop that iterates through a tuple of objects. Next, you have to call the methods without being concerned about which class type each object is. We assume that these methods actually exist in each class.

class India():
    def capital(self):
        print("New Delhi")
    def language(self):
        print("Hindi and English")

class USA():
    def capital(self):
        print("Washington, D.C.")
    def language(self):
        print("English")

class Europe():
    def capital(self):
        print("Brussels")
    def language(self):
        print("French")

obj_ind = India()
obj_usa = USA()
obj_eur=Europe()
for country in (obj_ind, obj_usa,obj_eur):
    country.capital()
    country.language()

output:
New Delhi
Hindi and English
Washington, D.C.
English
Brussels
French
Method Overriding in Python

v If the child class not satisfy the parent class method implementation then it is possible to override that method in the child class based on child class requirement.

v Whatever methods parent has by default available to the child through inheritance. Sometimes child may not satisfy with parent method implementation. Then child is allowed to redefine that method based on its requirement. This process is called overriding.

v It's an approach of re-implementing a parent classes method under the child class with the same signature.


The parent class method which is overridden is called overridden method.
The child class method which is overriding is called overriding method
.

The parent class method is called-------------overridden method
The child class method is called---------------overriding method
 
 §  When the child inherits the features from his parent, the child may be happy with those features of the parent but sometimes the child may not be happy with those features of the parent if the child is not satisfied with those features of the parent. then child Can override those features of the parent. this is nothing it is overriding.

 §  In the given example, the parent has three method such as the parent has taken the decision to purchase the hero bike but may be child not be happy with this decision of the parent, may be the child wants to buy another bike, then the child Can override the parent decision
  
class Parent:
    def property(self):
        print('Parent has Money,Gold')
    def purchaseBike(self):
        print('parent wants to purchase Hero Bike!')
    def marry(self):
        print('parent decide marry with Black girl!')

class Child(Parent):
    def purchaseBike(self):
        print('Child wants to purchase R1-5 Bike!')
    def marry(self):
        print('Child decide marry with White girl!')

#Creating Parent class object
print('With respect to parent object!.')
p=Parent()
p.property()
p.purchaseBike()
p.marry()
#Creating Child class object
print('With respect to child object!.')
c=Child()
c.property()
c.purchaseBike()
c.marry()

output:
With respect to parent object!.
Parent has Money,Gold
parent wants to purchase Hero Bike!
parent decide marry with Black girl!
With respect to child object!.
Parent has Money,Gold
Child wants to purchase R1-5 Bike!
Child decide marry with White girl!

Real example of Java Method Overriding

Consider a scenario, Bank is a class that provides functionality to get rate of interest. But, rate of interest varies according to banks. For example, SBI, ICICI and AXIS banks could provide 8%, 7% and 9% rate of interest.




class Bank:
    def getRateOfInterest(self):
        return 0

class SBI(Bank):
    def getRateOfInterest(self):
        return 7

class ICICI(Bank):
    def getRateOfInterest(self):
        return 8

class AXIS(Bank):
    def getRateOfInterest(self):
        return 9

#creating an object
s= SBI();
print('SBI Rate of Interest: ',s.getRateOfInterest())  
i= ICICI(); 
print('ICICI Rate of Interest: ',i.getRateOfInterest()) 
a= AXIS();  
print('AXIS Rate of Interest: ',a.getRateOfInterest())
output:
SBI Rate of Interest:  7
ICICI Rate of Interest:  8
AXIS Rate of Interest:  9

Another Example:

class Animal:
    def eating(self):
        print('Animal Eating!.')

class Lion(Animal):
    def eating(self):
        print('Lion is eating meat!.')

class Cow(Animal):
    def eating(self):
        print('Cow is eating grass!.')

#creating an object
a=Animal()
a.eating()
l=Lion()
l.eating()
c=Cow()
c.eating()

output:
Animal Eating!.
Lion is eating meat!.
Cow is eating grass!.


Overloading In Python 

 §  When we are using operator or method for different purpose then it is known as operator or method overloading. 

 §  Overloading refers to the ability of a function or an operator to behave in different 
        ways depending on the parameters that are passed to the function, or the operands 
        that the operator acts on.

There are 3 types of overloading 
1.     Operator Overloading
2.     Method Overloading 
3.     Constructor Overloading

Operator Overloading 
 §  Python allows us to change the default behavior of an operator depending on the operands that we use. This practice is referred to as "operator overloading".

 §  Python supports operator overloading.
operand1 + operand2

 §  when we are applying + operator between both operand if both operand numeric types then it will perform default behavior addition.

print(10+20)#the output:30  

 §  when we are applying + operator between both operand if both operand str types then you must have noticed its different behavior and then it will perform String concatenation.

print('hello'+'world')#the output:helloworld

 § when we are applying + operator between both operand if both operand list types then you must have noticed its different behavior and then it will perform list merge operation.

[10,20,30] + [40,50] = [10,20,30,40,50]

 §  It is possible because + operator is overloaded by both int class and str class
 * operator can be used for multiplication and string repetition purposes.

 §  If you want to represent any object as a string, then __str__method comes into picture.

 §  The __str__()method returns the string representation of the object.

 §  If you print any object, python compiler internally invokes the __str__ method on the object.

 §  So, overriding the __str__method, returns the desired output. 

class Point:
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y
    def __str__(self):
        return "({0},{1})".format(self.x,self.y)

#creating an object
p1=Point(10,20)
print(p1)
output:
(10,20)

Overloading the + Operator in Python

class Point:
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y
    def __str__(self):
        return "({0},{1})".format(self.x,self.y)

#creating first point object
p1=Point(10,20)
#creating second point object
p2=Point(30,40)
p3=p1+p2
print(p3)
p3=p1+p2
TypeError: unsupported operand type(s) for +: 'Point' and 'Point'

TypeError was raised since Python didn't know how to add two Point objects together.actually + operator doesn't know  what to do when we are apply between two point object.

 §  To achieve operator overloading, we define a special method in a class definition. The name of the method should begin and end with a double underscore (__). The + operator is overloaded using a special method named __add__
class Point:
    def __init__(self, x = 0, y = 0):
        self.x = x
        self.y = y
    def __str__(self):
        return "({0},{1})".format(self.x,self.y)
    def __add__self,other):
        x = self.x + other.x
        y = self.y + other.y
        return Point(x,y)

#creating first point object
p1=Point(10,20)
#creating second point object
p2=Point(30,40)
p3=p1+p2
print('Point1 =',p1)
print('Point2= ',p2)
print('Sum of Points= ',p3)
output:
Point1 = (10,20)
Point2= (30,40)
Sum of Points= (40,60)

What actually happens is that, when you do p1 + p2, Python will call p1.__add__(p2) which in turn is Point.__add__(p1,p2)

The following is the list of operators and corresponding magic methods.

OPERATOR      
MAGIC METHOD
+
__add__(self, other)
__sub__(self, other)
*
__mul__(self, other)
/
__truediv__(self, other)
//
__floordiv__(self, other)
%
__mod__(self, other)
**
__pow__(self, other)

Comparison Operators :

OPERATOR      
MAGIC METHOD
< 
__lt__ (self, other)
> 
__gt__ (self, other)
<=
__le__ (self, other)
>=
__ge__ (self, other)
==
__eq__ (self, other)
!=
__ne__ (self, other)



§  Overloading > and <= operators for Person class objects: 
p1>p2 i.e. p1 person is older than p2 person
p1<p2 i.e. p1 person is younger than p2 person
p1==p2 i.e. p1 person and p2 person both is equal in age.

class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __gt__(self,other):
        return self.age>other.age
    def __lt__(self,other):
        return self.age<other.age 
    def __eq__(self,other):
        return self.age==other.age 

#Creating first person object
p1=Person('Scott',50)
#Creating second person object
p2=Person('John',90)
if p1>p2:
    print(p1.name,'is older than',p2.name)
elif p1<p2:
    print(p2.name,'is older than',p1.name)
elif p1==p2:
    print(p1.name,'and',p2.name,'is equal in age')
output:
John is older than Scott
=======================
p1>p2= False
p1<p2= True
p1==p2 False




www.CodeNirvana.in

Powered by Blogger.

About

Site Links

Popular Posts

Translate

Total Pageviews