Python OOP Polymorphism Tutorial

In this tutorial we learn how to override parent class members inside a child class. We cover how to overload dunder methods, and also look at a list of common magic methods.

What is polymorphism?

Polymorphism is a big scary word that comes from the Greek “poly” meaning many, and “morphe” meaning form. It means that something can have many forms.

In the case of Object Oriented Programming, it means that an object can be treated as having many different types. Polymorphism enables a child class to define its own version of a member that’s also defined by its parent class.

In simple terms, polymorphism is when we override a built-in (magic) method.

tip If you come from a language such as C#, magic methods would be similar to operator overloading.

Polymorphism works with magic methods (dunder methods). An example of a dunder method would be the __init__() method.

Another example would be the + operator, which is actually shorthand for a dunder method called __add__() . The __add__() method uses polymorphic behaviour.

If the operands are integers, the method will do a mathematical addition. If the operands are strings, it concatenates the strings together.

Example:
num = 1 + 3         # 4 (int)
str = "1" + "3"  # 13 (string)

print("num = ", num, type(num))
print("str = ", str, type(str))

In the example above, we see polymorphism in action. The + operator is doing both arithmetic and concatenation.

Operator overloading

To override a dunder method we simply define a method with the same name as the method we want to override.

As an example, let’s consider the + operator. We know that its dunder method is __add__() , so we can define a method with the same name in our own class and make it do what we want.

Then when we use the + operator it will do what we specified in our method, instead of the default behavior.

Example:
class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # overwrite the __repr__ dunder
    def __repr__(self):
        return f"Dog named {self.name}, {self.age} years old"

    # overwrite the + operator
    def __add__(self, other):
        if isinstance(other, Dog):
            return Dog(name="Newborn", age=0)
        else:
            return "You can't breed a dog with that!"

daddy = Dog("Clyde", 3)
mommy = Dog("Bonnie", 3)

puppy = mommy + daddy
print(puppy)

When we use the + operator on the mommy and daddy objects, the interpreter executes our custom __add__() method in the Dog class and produces a new instance into the “puppy” object.

List of common magic (dunder) methods

The following tables list common magic, or dunder, methods.

Initialization and Construction:

NameDescription
__new__()Called in an object's instantiation.
__init__()Constructor method. Called by new .
__del__()Destructor method.

Unary operators and functions:

NameDescription
__abs__()Called by built-in abs() function.
__round__()Called by built-in math.round() function.
__floor__()Called by built-in math.floor() function.
__ceil__()Called by built-in math.ceil() function.
__trunc__()Called by built-in math.trunc() function.

Type Conversion:

NameDescription
__int__()Called by built-in int() method to convert to an int.
__float__()Called by built-in float() method to convert to float.

Strings:

NameDescription
__str__()Called by built-in str() method to return a string representation of a type.
__unicode__()Called by built-in unicode() method to return an unicode string of a type.
__format__()Called by built-in string.format() method to return a new style of string.
__dir__()Called by built-in dir() method to return a list of attributes of a class.
__sizeof__()Called by built-in sys.getsizeof() method to return the size of an object.

Attribute:

NameDescription
__getattr__()Called when the accessing a class attribute that does not exist.
__setattr__()Called when assigning a value to a class attribute.
__delattr__()Called when deleting a class attribute.

Operator:

NameDescription
__add__()Called on addition operation.
__sub__()Called on subtraction operation.
__mul__()Called on multiplication operation.
__div__()Called on division operation.
__mod__()Called on modulo operation.
__pow__()Called on calculating the power.

Augmented assignment:

NameDescription
__iadd__()Called on addition with assignment.
__isub__()Called on subtraction with assignment.
__imul__()Called on multiplication with assignment.
__idiv__()Called on division with assignment.
__imod__()Called on modulo with assignment.
__ipow__()Called on exponents with assignment.

Summary: Points to remember

  • Polymorphism is when a child class defines its own version of a method in a parent class.
  • Polymorphism in Python uses magic methods, otherwise known as dunder methods.
  • To override a magic method we create a method with the exact same name.