Previous: Operator Overloading & Special Methods

One of the four pillars of object-oriented programming: abstraction, encapsulation, inheritance, and polymorphism.

Polymorphism means that an object of a subclass can be passed to a parameter of a superclass type. A method may be implemented in several classes along the inheritance chain. Python decides which method is invoked at runtime. This is known as dynamic binding

We can use the same method, the same name, and same arguments to cause different things to happen according to the class in which we invoke a method. In object-oriented programming, this feature is known as polymorphism.

# Polymorphism

class GeometricObject:
    def __init__(self):
        print('GeometricObject created')

    def __str__(self):
        return 'Geometric Object'

class Circle(GeometricObject):
    def __init__(self):
        super().__init__()
        print('Circle created')

    def __str__(self):
        return 'Circle'

class Rectangle(GeometricObject):
    def __init__(self):
        super().__init__()
        print('Rectangle created')

    def __str__(self):
        return 'Rectangle'

# polymorphism in this function
def printObject(g):
    # Depend on the object g, that the __str__() calls
    # the __str__() belong to the own object
    print(g)

def main():
    c = Circle()
    r = Rectangle()
    printObject(c)
    printObject(r)

# Run the main function
main()

Output:

GeometricObject created
Circle created
GeometricObject created
Rectangle created
Circle
Rectangle

If o invokes a method p, Python searches the implementation for the method p in C1, C2, ..., Cn-1, and Cn, in this order, until it is found. Once an implementation is found, the search stops and the first-found implementation is invoked.

The method to be invoked is dynamically bound at runtime.

<aside> 💡

In simpler terms, Dynamic Binding basically two classes superclass and subclass, where a method in the superclass can be used in the subclass without overridden Since the method is not in the subclass, it locates the method with the similar name in the superclass and use it instead during the runtime of the program.

</aside>

Polymorphism with Dynamic Binding:

# Dynamic Binding in Class

class Person:
    # No __init__: use a default object
    def __str__(self):
        return "This is a Person"

    def display(self):
        print(self.__str__())

class Student(Person):
    def __str__(self):
        return "This is a Student"

def main():
    p = Person()
    s = Student()
    p.display()  # This line returns "This is a Person"
    s.display()  # This line returns "This is a Student"
    # Though the display() function does not exist in Class Student
    # This is Dynamic Binding

main()

Output:

This is a Person
This is a Student

Next Page: Abstract Classes & Abstract Methods