Session 20 : Polymorphism and Abstraction
Polymorphism
Greek word "poly"- Many , "morph" - Forms , polymorphism literally means "many forms." www.a2techschool.com
Object-Oriented Programming (OOP), polymorphism refers to the ability of objects of different types to respond to the same method call in different ways. In simpler terms, it allows a single interface or function to behave differently based on the object or context in which it is used.
In [ ]: # Jab chiz situation k hisab se alag alag dhang se behave kre
There are two types of polymorphism in Python:
1. Compile-time Polymorphism (Method Overloading): Not directly supported in Python but can be simulated.
2. Run-time Polymorphism (Method Overriding): Supported via inheritance and method overriding.
Method Overridding
Method overriding in Python occurs when a child class (or subclass) defines a method with the same name as a method in the parent class (or superclass). When the method is called on an instance of the child class, the child class's version of the method is executed instead of
the parent class's version.
In [1]: class Phone:
def __init__(self,price,brand,camera):
print("Inside phone constructor")
self.__price=price
self.brand=brand
self.camera=camera
def buy(self):
print("buying a phone")
class SmartPhone(Phone):
def buy(self):
print("Buying a smartphone") # Overriding the parent class's 'buy' method
In [2]: s=SmartPhone(3000,"apple",13)
Inside phone constructor
In [3]: s.buy()
Buying a smartphone
In [4]: # Super with method
class Phone:
def __init__(self,price,brand,camera):
print("Inside phone constructor")
self.__price=price
self.brand=brand
self.camera=camera
def buy(self):
print("buying a phone") # Method in the parent class
class SmartPhone(Phone):
def buy(self): # Overriding the buy() method in the child class
print("Buying a smartphone")
super().buy() # Call the parent class's buy() method using super()
In [5]: s2=SmartPhone(6000,"samsung",108)
Inside phone constructor
In [6]: s2.buy()
Buying a smartphone
buying a phone
Polymorphism with a Built-in Function**
Python’s built-in functions like len() work across various data types. This is an example of polymorphism in Python’s standard library.
In [126… # Polymorphism with built-in len() function
print(len("Hello"))
print(len([1, 2, 3]))
print(len({"key": "value"}))
# `len()` function is polymorphic because it can handle strings, lists, and dictionaries, even though each has a different structure.
5
3
1
Method Overloading
Python does not support traditional method overloading like other languages (e.g., Java), where methods can have the same name but different signatures (different number or types of parameters). However, you can simulate this behavior by using variable-length arguments (*args)
or by handling the logic inside a single method.
In [13]: # In Python, if you define two methods with the same name in a class, the latest definition will override the previous one.
class Shape:
def area(self,radius):
return 3.14*radius*radius
def area(self,l,b):
return l*b
In [14]: s=Shape()
In [127… s.area(2,4)
Out[127… 8
In [17]: s.area(2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[17], line 1
----> 1 s.area(2)
TypeError: Shape.area() missing 1 required positional argument: 'b'
In [18]: # using default parameters
class Shape:
def area(self,a,b=0):
if b == 0:
return 3.14*a*a # Circle case
else:
return a*b # Rectangle case
In [19]: s=Shape()
In [20]: s.area(2)
Out[20]: 12.56
In [21]: s.area(2,5)
Out[21]: 10
In [23]: # using variable argumenths *args
class Shape:
def area(self,*args):
if len(args)==1:
radius =args[0]
return 3.14*radius*radius www.a2techschool.com
elif len(args)==2:
l,b=args
return l*b
else:
return "Invalid Number of arguments"
In [24]: s=Shape()
In [25]: s.area(2)
Out[25]: 12.56
In [26]: s.area(2,5)
Out[26]: 10
Operator Overloading
Operator overloading in Python allows you to redefine the behavior of operators (+, -, *, etc.) for user-defined classes. This is done by defining special methods (also known as magic methods) such as add, sub, mul, and others within your class.
These methods enable objects of your class to behave in specific ways when they encounter operators.
In [ ]: +
In [27]: "Hello" + " World"
Out[27]: 'Hello World'
In [28]: 4 + 5
Out[28]: 9
In [29]: [1,2,3,4] + [4,5]
Out[29]: [1, 2, 3, 4, 4, 5]
In [30]: # Multiplying Vector with scalar
class Vector:
def __init__(self,x,y):
self.x=x
self.y=y
#operator overloading *
def __mul__(self,scalar):
return Vector(self.x *scalar,self.y*scalar)
def __str__(self):
return f"Vector({self.x},{self.y})"
In [31]: vec = Vector(3,4)
In [33]: result = vec *2
In [35]: print(result)
Vector(6,8)
Duck Typing
Duck typing is a concept in dynamic programming languages, such as Python, where the type or class of an object is determined by its behavior (methods and properties) rather than by explicitly checking the object’s type or inheritance hierarchy. The term is derived from the saying:
"If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck."
In [ ]: # we are determining object by its behaviour , rather than explicitly checking the objects type or inheritance hierarchy
In [37]: class Dog:
def speak(self):
return " Woof !"
class Cat:
def speak(self):
return "Meow!"
class Duck:
def speak(self):
return " Quack!"
# Duck typing : We are not checking the type of animal
def make_animal_speak(animal):
print(animal.speak())
In [38]: dog=Dog()
cat=Cat()
duck=Duck()
In [39]: make_animal_speak(dog)
Woof !
In [40]: make_animal_speak(cat)
Meow!
In [42]: make_animal_speak(duck)
Quack!
Abstraction
Abstraction is a concept used in various fields, including computer science, philosophy, and art, and it generally refers to simplifying complex systems by focusing on the essential features and hiding unnecessary details. The goal is to present only the relevant aspects to the user,
making it easier to interact with or understand the system.
In Object-Oriented Programming (OOP), abstraction refers to the process of hiding the complex implementation details of an object and exposing only the necessary and relevant features. It allows developers to work with higher-level, simplified interfaces while the underlying complexity
remains hidden.
Purpose: To reduce complexity and improve code manageability by focusing on what an object does, rather than how it does it.
Abstract Method:
An abstract method is a method that is declared but contains no implementation. It acts as a placeholder in a class, meant to be overridden by any concrete subclass. You cannot instantiate a class with an abstract method directly.
Abstract methods are usually part of abstract classes, which cannot be instantiated directly either. These methods define a required interface that must be implemented by any subclass.
Purpose: Enforces that subclasses implement the method.
Syntax: In Python, abstract methods are defined using the @abstractmethod decorator inside an abstract class (which uses the ABC from the abc module).
In [49]: from abc import ABC, abstractmethod # abc - abstract base class
In [55]: # Abstract Method -
# Purpose - Enforces that subclass implement the method
"""
@abstractmethod
def method_name:
pass
"""
Out[55]: ''
In [ ]: # Concrete Methods
class Vehicle:
def start_engine(self):
print (" Vehicle engine starts")
www.a2techschool.com
class Car(Vehicle):
def start_engine(self):
print("car engine starts")
class Bike(Vehicle):
def start_engine(self):
print("bike engine starts")
In [51]: class Vehicle(ABC): # Abstract class -> class which is having atleast one abstract method
@abstractmethod
def start_engine(self):
pass
class Car(Vehicle):
def start_engine(self):
print("car engine starts")
class Bike(Vehicle):
def start_engine(self):
print("bike engine starts")
In [52]: car=Car()
bike=Bike()
In [53]: car.start_engine()
car engine starts
In [54]: bike.start_engine()
bike engine starts
abstract class (vehicle) defines a high level behaviour start_engine() but does not provide its implementation
The subclasses Car and Bike has to provide implementation
In [74]: #highlevel
class BankApp(ABC):
def database(self):
print("connected to database")
@abstractmethod
def security(self):
pass
@abstractmethod
def Id_verification(self):
pass
In [75]: #low level
#If the class do not include the abstract method from parent class , the object of that class cant be created
class MobileAPP(BankApp):
def mobile_login(self):
print("login to mobile")
In [76]: mob = MobileAPP()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[76], line 1
----> 1 mob = MobileAPP()
TypeError: Can't instantiate abstract class MobileAPP with abstract methods Id_verification, security
In [77]: #low level
# The class has to include all the abstract methods from the parent class
class MobileAPP(BankApp):
def mobile_login(self):
print("login to mobile")
def security(self):
print("Mobile Security")
In [78]: mob = MobileAPP()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[78], line 1
----> 1 mob = MobileAPP()
TypeError: Can't instantiate abstract class MobileAPP with abstract method Id_verification
In [72]: mob.database()
connected to database
In [73]: mob.security()
Mobile Security
In [79]: #low level
class MobileAPP(BankApp):
def mobile_login(self):
print("login to mobile")
def security(self):
print("Mobile Security")
def Id_verification(self):
print("Adhar Verified")
In [80]: mob = MobileAPP()
In [82]: mob.Id_verification()
Adhar Verified
In [83]: mob.database()
connected to database
In [85]: # You can't create Object of the Abstract Class
bank=BankApp()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[85], line 1
----> 1 bank=BankApp()
TypeError: Can't instantiate abstract class BankApp with abstract methods Id_verification, security
In python abstract methods are meant to be placeholders for the fucntionality that must be implemented in subclass
python does not allows you to add implementation to an abstract method
In [91]: # Abstract method with implementation( Not Recommended )
class Animal(ABC):
@abstractmethod
def sound(self):
print(" This is default sound ") # abstract method with implementation www.a2techschool.com
def move(self):
return " I can move" # regular concrete method
class Dog(Animal):
def sound(self):
super().sound()
return " woof!"
class Cat(Animal):
def sound(self):
return "Meow"
In [92]: dog=Dog()
cat=Cat()
In [93]: dog.sound()
This is default sound
Out[93]: ' woof!'
In [94]: cat.sound()
Out[94]: 'Meow'
Even though the abstract method provides default implementation, subclass are still required to implement the method
In [ ]: # Concepts of OOPS from RAVAN
Attributes - Knowledge, heads ,secrete_power
Imndrajit
god_powers and demon_powers
In [117… from abc import ABC, abstractmethod
# Abstraction( Abstract class)
class Powers(ABC):
@abstractclassmethod
def use_power(self):
pass
# Ravana Class (Parent Class)
class Ravana(Powers):
def __init__(self,heads,knowledge,secret_power):
self.heads=heads
# Encapsulation : Private attribute(secret_power)
self.__secret_power=secret_power
self.knowledge = knowledge
#getter for private attribute
def reveal_secret_power(self):
return self.__secret_power
def use_power(self): # Method for abstract method(Abstraction)
return " Using Ravanans Power !"
def speak(self):
return f"Ravana speaks with {self.heads} heads filled with knowledge"
# Multiple inhertiance
class GodPowers:
def use_god_power(self):
return f"Ravana uses divine power inherited from gods"
class DemonPowers:
def use_demon_power(self):
return f"Ravana uses demon power inherited from demons"
# Ravana sons( Inheritance)
class Indrajit(Ravana,GodPowers,DemonPowers):
def __init__(self,heads,knowledge,secret_power,weapon):
super().__init__(heads,knowledge,secret_power) # Calls the parent constrctor(Ravana)
self.weapon=weapon # Unique attribute of Indrajit
# method overriding(polymorphism)
def use_power(self):
return f"Indrajit uses his special weapon :{self.weapon}"
def display_powers(self):
return f"{self.use_god_power()} and {self.use_demon_power()}"
In [118… # object creation of parent class(Ravana)
ravana = Ravana(heads=10,knowledge="Master of Scriptures",secret_power="Immortality")
In [119… # Encapsulation
print("Ravana's Secret Power : " , ravana.reveal_secret_power())
Ravana's Secret Power : Immortality
In [120… #Inheritance and polymorphism: Creating object of child class
indrajit=Indrajit(heads=1,knowledge="Master of Sorcery",secret_power="Invisibility",weapon="Brahmastra")
In [121… # accessing overidden methods
indrajit.use_power()
Out[121… 'Indrajit uses his special weapon :Brahmastra'
In [122… indrajit.display_powers()
Out[122… 'Ravana uses divine power inherited from gods and Ravana uses demon power inherited from demons'
In [123… ravana.use_power()
Out[123… ' Using Ravanans Power !'
In [124… ravana.speak()
Out[124… 'Ravana speaks with 10 heads filled with knowledge'
In [ ]: