{ Special Methods and Polymorphism. }


By the end of this chapter, you should be able to:

  • Add special methods to classes
  • Define and explain how to implement polymorphism in a class
  • Understand how to add custom properties and methods to built in data types in Python

Special methods for python objects

When we discuss special (also called "magic") methods, we are commonly referring to methods that contain a "dunder" (double underscore) like __init__. You have actually used quite a few of these under the hood, but you can implement your own for classes you create. Let's see a couple:

__str__ - what is evaluated when print is called

__len__ - what is evaluated when len is called

__del__ - what is evaluated when del is called

__doc__ - see the docstring for a value

__class__ - see what class created this object

There also exists another method called __repr__ which is similar to __str__; you can read about the differences here

You can read more about these here. Pay close attention to the differences between __repr__, __str__ and __format__


One of the key principles in Object Oriented Programming is polymorphism. This is the idea that an object can take on many (poly) forms (morph).

A very common example you will see of Polymorphism is the + operator. If we do 5 + 3 in Python our result will be 8 as the operator knows to add the two numbers. But if we do "8" + "3" Python knows to concatenate the values since they are strings. This single operator can take on many different forms, depending on the types it is working with!

You can see polymorphism applied when there is the same operation used for objects in different classes. Let's see another example!

sample_list = [1,2,3]
sample_tuple = (1,2,3)
sample_string = "awesome"


These are three different classes that have the same operation applied to them!

A common implementation of this is to have a method in a base (or parent) class that is overriden by a subclass. Each subclass will have a different implementation of the method. When the superclass/parent class method is called, it chooses which method to run depending on the subclass/child class. Let's look at a common example:

class Pet():
    def talk():
        raise NotImplementedError("Subclass needs to implement this method")

class Dog(Pet):
    def talk(self):
        return "WOOF!"

class Cat(Pet):
    def talk(self):
        return "MEOW!"

To implement polymorphism you do not need a superclass / parent class. It is only when you are using inheritance and polymorphism together that it is useful to ensure that the subclass implements its own version of the method.

For more on polymorphism, check out these articles:




Add custom properties / methods to built in data types in Python

In Python, you can't manipulate base classes for native data types in the same way. However, you can create a new class which extends the built in class, and add methods to the class you've created. To do this, you'll need to import the builtins module and manipulate the class you're interested in.

import builtins

# Extended subclass
class extend_str(str):
    def first_last_character(self):
        return self[0] + self[-1]

# Overwrite the str class on builtins with the custom class defined above
builtins.str = extend_str

str(0123).first_last_character() # '03'

str("awesome").first_last_character() # 'ae'

"awesome".first_last_character() # 'str' object has no attribute 'first_last_character'

Note that in the example above, you can't use your custom method on strings unless they're explicitly created by being passed into the str class. In short, this approach is cumbersome and not foolproof. But that's probably by design: you shouldn't be trying to modify these classes in the first place!

When you're ready, move on to Object Oriented Programming in Python Exercises


Creative Commons License