Some light on Magic (or Dunder) Methods in Python

moodayday™
AI³ | Theory, Practice, Business
5 min readSep 9, 2019

--

In Python, there is a special kind of methods affectionately called magic methods.

These are methods which name has two underscores as prefix and suffix. Because of this, they, even more, are known by the cute name dunder methods. Dunder here is simply a creative short name for these “double underscores” methods.

Here are a few examples for magic methods: __init__, __add__, __len__, __repr__ etc.

Now you might ask, what is so magical about these methods anyway!?. Well, one thing I know for sure is that they are special in the sense that you don’t need to call them directly as you do for other methods: Python calls them for you when it needs to know how you want some specific things (object initialization, representation, etc) should be handled.

The best way to get familiar with this funny magical methods thing is to dive right into with some examples.

We start from:

>>> class Person: pass

Here we create a simple class with no field or method other than the ones inherited from the base Object class. Let’s make this class our playground.

Constructing/Initializing object with __init__

Now we can add some fields using the magic method __init__()

>>> class Person:
def __init__(self, name, surname):
self.name = name
self.surname = surname

The __init__ method for initialization is invoked without any call, when an instance of a class is created, like constructors in certain other programming languages such as C++, Java, C#, PHP etc.

It should be noted that the first argument, namely the self parameter is mandatory and should be followed by the list of initialization values.

Handling object representation

Now let’s print our object:

>>> print(p)
<__main__.Person at 0x1110ceda0>

The above snippet of code prints only the memory address of the Person object. In order to alter how our Person objects are represented when we ask Python to print them, let’s add a __repr__ method to represent our class.

>>> class Person:
def __init__(self, name, surname):
self.name = name
self.surname = surname

def __repr__(self):
return self.__class__.__name__ + ': ' + self.surname.capitalize() + ' ' + self.name.capitalize()
>>> dan = Person('Amouw', 'daniel'); dan
Person: Daniel Amouw

This is a much representation of the object: it gives us the name of the class and the values of the properties of the object. It would certainly be much more useful than the object’s address in memory.

Implementing this method alters the way Python represents our objects of this class when we call print(), str() or repr() functions on them.

Now, __repr__ is not the only dunder method you can use for altering the representation of a class. You’ve got the __str__ method as well! It does almost the same thing but here is the slight difference in purpose:

  • __repr__: the goal of __repr__ is to be unambiguous. This is a geek-representation of the object that can be very helpful during debugging.
  • __str__: the goal of __str__ is to be readable for the user to know the object without too much problem. It’s purpose is to be nice to read while presenting the object.

I mean, this:

>>> class Person:
...
def __str__(self):
return "I'm " + self.name + " "+ self.surname + "."

…would be a pretty good implementation for __str__.

That said, I should also add that if __repr__ is defined, and __str__ is not, the object will behave as though __str__ = __repr__. It’s a good practice to always implement at least the __repr__ dunder method for any class you use.

Note that once the __str__ is implemented, it will be used during calls to print() and str() functions on the object of the class while __repr__ will be called when you call repr() on these objects.

How to add our objects

Now we describe how Python should handle the addition of two objects of our brand-new class. For that we should add __add__ magic method to Person class :

>>> class Person:
def __init__(self, name, surname):
self.name = name
self.surname = surname

def __repr__(self):
return self.name.capitalize() + ' ' + self.surname.capitalize()

def __add__(self, other):
return Person(self.name, other.surname)
>>> father = Person('Akakpo', 'Comlan')
>>> mother = Person('Tchaley', 'Dodo')
>>> child = father + mother; child
Akakpo Dodo

Implementing iteration: __len__, __getitem__,

Now we create a new class called Group which will be, like you’ve probably guessed a group of people:

>>> class Group: 
def __init__(self, name, people):
self.name = name
self.people = people

def __repr__(self):
return self.__class__.__name__ + ':'+self.name+'|'+self.people

def __str__(self):
return "Group " + self.name + " with members " + self.people

def __len__(self):
return len(self.people)

def __getitem__(self, index):
return "Person " + str(index) + ": " + str(self.people[index])

def __add__(self, other):
return Group(self.name, self.people + other.people)
>>> p0 = Person('Aliko', 'Dangote')
>>> p1 = Person('Bill', 'Gates')
>>> p2 = Person('Warren', 'Buffet')
>>> p3 = Person('Elon', 'Musk')
>>> p4 = Person('Jack', 'Ma')
>>> g = Group('__VIP__', [p0, p1, p2, p3, p4])>>> len(g)
5
# Iterating through our group object just like a list>>> for _ in g: print(_)
Person 0: Aliko Dangote
Person 1: Bill Gates
Person 2: Warren Buffet
Person 3: Elon Musk
Person 4: Jack Ma

In this example, the iteration is made possible thanks to the implementation of the __len__, __getitem__ dunder methods.

We can really fly with their magic.

And the best thing is…

There are even more dunder methods!

Oh yes!

In our example, we created simple classes which the only parent is the Object base class (every class in Python is by default a subclass of Object).

You can check the list running the function dir() with an object or a class name as an argument to see the magic methods available to be implemented.

This instruction for example,

>>> dir(int)

…will give you a long list of the magic methods defined for the type int. Imagine what you can do with this if you happen to need to subclass the type int in your application.

Try it! Play with it… until you see why everybody say they are so magical!

--

--