What is Polymorphism in Python? Explained with an Example
February 9, 2025

What is Polymorphism in Python? Explained with an Example

Polymorphism is an object-oriented programming principle (OOP), which helps you write high-quality, flexible, maintenance, repeatedly used, tested and read software. If you plan to work with object-oriented software, it is important to understand polymorphism.

What is polymorphism?

Word polymorphism obtained from Greek and means “the presence of several forms”:

  • Paul = a lot

  • Morph = form

When programming, polymorphism is the ability of an object to take different formsField

The key advantage of polymorphism is that it allows us to write more general And reusable code. Instead of writing a separate logic for different classes, we determine the general behavior in the parent class and allow children to reduce them as necessary. This eliminates the need for excessive if-else Checks, making the code more supported and expanded.

MVC Frameworks, such as Django, use polymorphism to make the code more flexible. For example, Django supports various databases such as SQLite, MySQL and PostgreSQL. Typically, each database requires various code for interacting with it, but Django provides a single API database that works with all of them. This means that you can write the same code for database operations, regardless of which database you use. So, if you run the project with SQLite, and then switch to PostgreSQL, you will not need to rewrite most of your code, thanks to polymorphism.

In this article, in order to simplify understanding, I will show you a bad example of a code without polymorphism. We will discuss the problems that this bad code causes, and then solve problems, refracting the code for the use of polymorphism.

(By the way, if you find out better from the video, check my polymorphism in Python YouTube.

First, an example without polymorphism:

class Car:
    def __init__(self, brand, model, year, number_of_doors):
        self.brand = brand
        self.model = model
        self.year = year
        self.number_of_doors = number_of_doors

    def start(self):
        print("Car is starting.")

    def stop(self):
        print("Car is stopping.")
class Motorcycle:
    def __init__(self, brand, model, year):
        self.brand = brand
        self.model = model
        self.year = year

    def start_bike(self):
        print("Motorcycle is starting.")

    def stop_bike(self):
        print("Motorcycle is stopping.")

Suppose we want to create a list of vehicles, then go through it and conduct an inspection on each vehicle:


vehicles = [
    Car("Ford", "Focus", 2008, 5),
    Motorcycle("Honda", "Scoopy", 2018),
]


for vehicle in vehicles:
    if isinstance(vehicle, Car):
        print(f"Inspecting {vehicle.brand} {vehicle.model} ({type(vehicle).__name__})")
        vehicle.start()
        vehicle.stop()
    elif isinstance(vehicle, Motorcycle):
        print(f"Inspecting {vehicle.brand} {vehicle.model} ({type(vehicle).__name__})")
        vehicle.start_bike()
        vehicle.stop_bike()
    else:
        raise Exception("Object is not a valid vehicle")

Pay attention to the ugly code inside for loop! Because vehicles This is a list of any type of object, we must find out with what type of object we are dealing with each cycle before we can access any information at the facility.

This code will continue to become increasingly ugly, since we add more types of vehicles. For example, if we expanded our code base to enable the new Plane class, then we needed modify (and potentially break) existing code – we would have to add another conditional check to for a loop for aircraft.

Presenting: polymorphism …

Cars and motorcycles – both cars. They both have some common properties and methods. So, let’s create a parental class that contains these common properties and methods:

Parental class (or “SuperClass”):

class Vehicle:
    def __init__(self, brand, model, year):
        self.brand = brand
        self.model = model
        self.year = year

    def start(self):
        print("Vehicle is starting.")

    def stop(self):
        print("Vehicle is stopping.")

Car And Motorcycle Now it can inherit from VehiclePole, let’s create classes of the child (or “subclasses”) Vehicle Superclass:

class Car(Vehicle):
    def __init__(self, brand, model, year, number_of_doors):
        super().__init__(brand, model, year)
        self.number_of_doors = number_of_doors

    

    def start(self):
        print("Car is starting.")

    def stop(self):
        print("Car is stopping.")
class Motorcycle(Vehicle):
    def __init__(self, brand, model, year):
        super().__init__(brand, model, year)

    

    def start(self):
        print("Motorcycle is starting.")

    def stop(self):
        print("Motorcycle is stopping.")

Car And Motorcycle Both expand VehicleHow are it vehicles. But what’s the point in Car And Motorcycle Both expand Vehicle If they are going to implement their own versions start() And stop() Methods? Look at the code below:


vehicles = [Car("Ford", "Focus", 2008, 5), Motorcycle("Honda", "Scoopy", 2018)]


for vehicle in vehicles:
    if isinstance(vehicle, Vehicle):
        print(f"Inspecting {vehicle.brand} {vehicle.model} ({type(vehicle).__name__})")
        vehicle.start()
        vehicle.stop()
    else:
        raise Exception("Object is not a valid vehicle")

In this example:

  • We have a list vehiclescontaining copies of both Car And MotorcycleField

  • We protrude through each vehicle in the list and conduct a general check on each.

  • The check process includes the launch of the car, check its brand and model, and then stops it.

  • Despite the fact that vehicles have different types, polymorphism allows us to consider them all as cases Vehicle variety. Specific implementations start() And stop() Methods for each type of car are called dynamically during execution, based on the actual type of each vehicle.

Because the list can only contain objects that expand Vehicle Class, we know that each object will share some common areas and methods. This means that we can safely call them without worrying about whether each specific vehicle has these fields or methods.

This demonstrates how polymorphism allows you to write the code in a more general and flexible way, which allows you to easily expand maintenance, since new types of vehicles are added to the system.

For example, if we want to add another car to the list, we do not need to change the code used to inspect vehicles (“client code”). Instead, we can just prolong our code base (that is, create a new class), without modification Existing code:

class Plane(Vehicle):
    def __init__(self, brand, model, year, number_of_doors):
        super().__init__(brand, model, year)
        self.number_of_doors = number_of_doors

    def start(self):
        print("Plane is starting.")

    def stop(self):
        print("Plane is stopping.")

vehicles = [
    Car("Ford", "Focus", 2008, 5),
    Motorcycle("Honda", "Scoopy", 2018),

    

    Plane("Boeing", "747", 2015, 16),

    
]

The code for the implementation of the inspections of the vehicle should not change in order to take into account the plane. Everything is still working, without the need to change our verification logic.

Conclusion

Polymorphism allows customers to relate to various types of objects the same. This significantly improves the flexibility of software and maintenance of software, since new classes can be created without the need to modify (often adding additional if/else if blocks) existing working and tested code.

Further training

Polymorphism is associated with many other object-oriented programming principles, such as Dependence injection And open Hard principle. If you want to master the OOP, check out my UDEMY:

If you prefer a video book, watch my books:

Thank you for reading 🙂

Source link

Leave a Reply

Your email address will not be published. Required fields are marked *