Python

Polymorphism

YouTube

Object polymorphism is a concept in object-oriented programming that refers to the ability of a single object to take on multiple forms. This is achieved through inheritance, where an object can inherit properties and behaviour from a parent object, and then modify or override them to suit its own needs.

Polymorphism Definition:

Polymorphism is a fundamental concept in object-oriented programming (OOP) that allows objects of different classes to be treated as if they were objects of a common superclass. It enables you to write code that can work with objects of various types in a consistent way.

Polymorphism Types:

Method Overloading: In some programming languages, method overloading allows a class to have multiple methods with the same name but different parameters. However, in Python, method overloading is achieved using default arguments and variable arguments.

Method Overriding: Occurs when a subclass provides a specific implementation of a method that is already defined in its superclass. The overridden method in the subclass is called instead of the superclass method when the object is of the subclass type.

Duck Typing: Python follows a principle known as “duck typing,” which states that an object’s suitability is determined by its behaviour rather than its class. If an object behaves like a certain class (by implementing its methods), it is considered to be of that class.

Polymorphism in Action:
class Animal: 
    def speak(self): 
       pass 

class Dog(Animal): 
    def speak(self): 
        return "Woof!"

class Cat(Animal): 
    def speak(self): 
        return "Meow!" 

class Duck(Animal): 
    def speak(self):
        return "Quack!" 

# Polymorphism in action 

animals = [Dog(), Cat(), Duck()] 

for animal in animals: 
    print(animal.speak())
Benefits of Polymorphism:
  • Code Reusability: Polymorphism allows you to define common behaviours in superclass methods, which can be inherited and customised by subclasses.
  • Flexibility: You can write code that works with objects of different types, promoting more modular and adaptable designs.
  • Simplification: Polymorphism reduces the need for extensive conditional statements by treating objects uniformly based on their common behaviours.
Interface and Abstract Classes:

Python does not have explicit interfaces like some other languages. Instead, abstract base classes (ABCs) can be used to define a common interface for a group of related classes.

Extending Polymorphism:

You can extend polymorphism to custom classes by defining methods with the same name and purpose, even if the internal logic differs. This allows you to create new classes that integrate seamlessly with existing code.

Polymorphism and Inheritance:

Polymorphism often goes hand in hand with inheritance, as it enables different subclasses to provide their own implementations of methods inherited from a common superclass.

Looking at our Vehicle example below, we can already see that there are a few different ways we can use polymorphism from our objects. Our initial Vehicle base class has three methods which all the sub classes override in their own class. Due to this, we can loop through all the objects of these and call a singular method, which will allow us to access the Vehicle ID for all objects.

from abc import abstractmethod

class Vehicle:
    def __init__(self, model, make, year, weight):
        self.model = model
        self.make = make
        self.year = year
        self.speed = 0
        self.weight = weight
        self._vehicle_ID_number = None
        
    def move(self):
        if self.year > 1970:
            self.speed += 30
            print("You are going 30mph!")
            
    def get_vehicle_ID(self):
        return self._vehicle_ID_number
            
    @abstractmethod
    def slow_down(self):
        pass

class Car(Vehicle):
    _count = 0
    def __init__(self, model, make, year, weight):
        super().__init__(model, make, year, weight)
        Car._count += 1        
        self._vehicle_ID_number = Car._count
    
    def slow_down(self): 
        if self.speed >= 1:
            self.speed -= 5

class Lorry(Vehicle):
    _count = 0
    def __init__(self, model, make, year, weight):
        super().__init__(model, make, year, weight)
        Lorry._count += 1
        self._vehicle_ID_number = Lorry._count
        
    def slow_down(self): 
        if self.speed >= 1:
            if self.weight > 100:
                self.speed -= 1
            elif self.weight > 75:
                self.speed -= 2
            elif self.weight > 50:
                self.speed -= 3
            else: 
                self.speed -= 4
    
car = Car("1 Series", "BMW", 2016, 24)
car2 = Car("A1", "Audi", 2019, 27)
lorry = Lorry("Big Lorry", "Volkswagen", 2020, 74)
lorry2 = Lorry("Small Lorry", "Volkswagen", 2020, 54)

vehicles = [car, car2, lorry, lorry2]

for i, vehicle in enumerate(vehicles):
    print(f"Vehicle Object {i}: Vehicle ID is {vehicle.get_vehicle_ID()}")