3 Minutes Python | Magic/Dunder Methods

Jay Shi
One Bit At A Time
Published in
3 min readDec 31, 2019

What is a dunder method and why does it make our code more elegant?

Photo by Cristian Escobar on Unsplash

WHAT ARE DUNDER METHODS?

What is the dunder methods? The dunder method stands for a double underscore method. When we write a Dunder method in python, we write it like __<function-name>__

When we write a class in Python, we need to write def __init__(self) . Here, the __init__ method is a dunder method.

But why do we need to know about Dunder methods, you might ask. Well, implementing dunder methods in your class will make your object behave like a native python object. The following example will show why and how.

EXAMPLES:

Let’s say now we need to create a class that keeps track of the time needed to complete a task.

class Time:
def __init__(self, time, task):
self.time = time
self.task = task

But let’s say now we realize the time can be incremented or decremented. We can simply add a new instance method called add_time:

class Time:
...
def add_time(self, addtional_time):
return self.time + additional_time
time_1 = Time(10)# new_time now evaluates to be 30
new_time = time_1.add_time(20)

But what if we can express it more elegantly by just using ‘+’ operation? How do we achieve this? By using the dunder method, __add__. This made our Time class behave more like a built-in class in Python.

class Time:
...
def __add__(self, addtional_time):
self.time + additional_time
return self.time
time_1 = Time(10)# new_time now evaluates to be 30
new_time = time_1 + 20

Similarly, when we need to print the Time object, instead of implementing a new instance method, we can simply use __str__

class Time:
...
def __str__(self):
return '{} requires {}s'.format(self.task, self.time)
# prints out 'Breathing requires 10s'
print(Time(10, 'Breathing'))

Now, let’s say if we want to access/modify a property of Time using the square brackets, we can use __getitem__ and __setitem__

class Time:
...
def __getitem__(self, key):
return getattr(self, key)
def __setitem__(self, key, value):
setattr(self, key, value)
return getattr(self, key)
time_breathing = Time(10, 'Breathing')# this evaluates to be 10
time_breathing['time']
# now time_breathing.task is evaluated as 'Blinking'
time_breathing['task'] = 'Blinking'

Now if we want to access how long the task takes by simply using len() function, we can use ‘__len__’

class Time:
...
def __len__(self):
return self.time
# this evaluates to be 10
len(Time(10, 'Breathing'))

RECAP

In this post, we learned about why and how to use dunder methods (double underscore methods). We learned that by using dunder methods, our class behaves more like a built-in Python class.

The following code snippet is a recap of what dunder methods we have used in the example.

class Time:
def __init__(self, time, task):
self.time = time
self.task = task
# enables '+' operation
def __add__(self, addtional_time):
return self.time + additional_time
# enables str() and print(). print() uses str() under the hood
def __str__(self):
return '{} requires {}s'.format(self.task, self.time)
# enables square brackets operation. e.g. time_1['time']
def __getitem__(self, key):
return getattr(self, key)
# enables square bracktes operation. e.g. time_1['time'] = 20
def __setitem__(self, key, value):
setattr(self, key, value)
return getattr(self, key)
# enables len()
def __len__(self):
return self.time

--

--

Jay Shi
One Bit At A Time

Software Engineer @ Google. I write about Python tutorials and stuff that can help you become a better software engineer.