Python Polymorphism
Polymorphism in Python is a principle of object-oriented programming that allows methods, functions, or operators to perform different actions based on the type of the input.
What is Polymorphism in Python?
Polymorphism allows the same method name to be used across different classes, with each class providing its own implementation of the method.
The key difference is the data types and number of arguments used in function. This means that the same function name can be used for different types of operations, as long as the argument types and the number of arguments match the function signature that we want to invoke.
There are two main types of polymorphism in Python:
- Function Polymorphism
- Class Polymorphism
1. Function Polymorphism in Python
Function Polymorphism is the ability of certain built-in functions in Python to run on different types of objects given as arguments.
A great example of this is the len()
function, which can be used with various data types such as strings, lists, and tuples to return the length of the object
print(len("TutorialReference"))
print(len(["Python", "Java", "JavaScript", "C#"]))
print(len({"Name": "Tom", "State": "New York"}))
Output:
17
4
2
Notice that many data types (such as string, list, tuple, set, and dictionary) can work with the len()
function.
However len()
function returns specific information about specific data types. Actually:
len(str)
returns the length of the stringlen(list)
returns the number of items of the listlen(dict)
returns the number of keys of the dictionary
2. Class Polymorphism in Python
Class Polymorphism is the ability of different classes to implement the same method name, even though the method may perform different actions depending on the class it is called upon.
This concept is closely related to the principle of inheritance, where a child class can override a method from its parent class, which is known as method overriding.
Discover more about Python Inheritance.
For example, let's create two classes Cat
and Dog
that share a similar structure and have the same method names info()
and make_sound()
.
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print(f"I am a cat. My name is {self.name}. I am {self.age} years old.")
def make_sound(self):
print("Meow")
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print(f"I am a dog. My name is {self.name}. I am {self.age} years old.")
def make_sound(self):
print("Bark")
cat1 = Cat("Luna", 3)
dog1 = Dog("Charlie", 5)
for animal in (cat1, dog1):
animal.make_sound()
animal.info()
animal.make_sound()
Output:
Meow
I am a cat. My name is Luna. I am 3 years old.
Meow
Bark
I am a dog. My name is Charlie. I am 5 years old.
Bark
We have not created a common superclass or linked the classes together in any way. Even then, we can pack these two different objects into a tuple and iterate through it using a common animal variable.
This is possible thanks to polymorphism!
Relation between Polymorphism and Inheritance in Python
In Python, inheritance is a mechanism that allows a new class (child class) to inherit properties and behaviors from an existing class (parent class). This relationship is established through the syntax class ChildClass(ParentClass)
, where ChildClass
can access all the attributes and methods from the ParentClass
.
On the other hand, Polymorphism allows objects of different classes to be treated as objects of a common superclass. This means that the same method can be called on different objects, and the appropriate version of the method will be executed based on the actual type of the object at runtime
The relationship between polymorphism and inheritance in Python is that inheritance provides the basis for polymorphism. When a child class overrides a method from its parent class, it's an example of method overriding, which is a form of polymorphism. The child class's method becomes the default implementation, and it can be further specialized by any further descendant classes.
For example:
from math import pi
class Shape:
def __init__(self, name):
self.name = name
def area(self):
pass
def fact(self):
return "This is a two-dimensional shape."
def __str__(self):
return self.name
class Square(Shape):
def __init__(self, length):
super().__init__("Square")
self.length = length
def area(self):
return self.length**2
def fact(self):
return "Squares have each angle equal to 90 degrees."
class Circle(Shape):
def __init__(self, radius):
super().__init__("Circle")
self.radius = radius
def area(self):
return pi*self.radius**2
square_obj = Square(4)
circle_obj = Circle(7)
print(circle_obj)
print(circle_obj.fact())
print(square_obj.fact())
print(circle_obj.area())
Output:
Circle
This is a two-dimensional shape.
Squares have each angle equal to 90 degrees.
153.93804002589985
Notice that in this example:
- Methods like
__str__()
, which have not been overridden in the child classes, are used from the parent class. - Thanks to polymorphism, the Python interpreter automatically identifies that the
fact()
method for objectsquare_obj
(which an instance of theSquare
class) has been overridden by a subclass. Consequently, it uses the overridden version defined in the subclass. - The
fact()
method for objectcircle_obj
isn't overridden and it is uses the implementation provided in the Parent Shape class.
Method Overloading is a way to create multiple methods with the same name but different arguments.
Method Overloading is NOT possible in Python.
But you can do Operator Overloading.