Link Search Menu Expand Document

Dunder methods

Magic methods or dunder methods in Python are those that begin and end with __, such as __init__. The name dunder comes from double underscore.

These are methods defined by Python that can be used internally or associated with operators. For example:

  • If you use () under the hood it calls __init__.
  • If you use +, __add__ is called.
  • If you use ==, __eq__ is called.

Depending on what you want to do and your class, you may want to define these dunder methods. This is very powerful, as it allows you to define the behavior of your class.

Next, we will see the most known ones. We will use as an example a Point class with two attributes x and y. This class represents a point in space in two dimensions.

Method __init__. As we have seen previously, it is the constructor and allows us to create the object. It is called when using ().

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(1, 2)

print(p.x) # 1
print(p.y) # 2

Method __del__. It can be seen as the opposite of __init__. One constructs, one destroys. So you can implement the logic of your destructor.

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __del__(self):
        print("Object destroyed")

This method will be called when you destroy your object with del. You decide what to put there. It is common to see it in places where it is important to free resources after you are done.

p = Point(1, 2)
del p
# Object destroyed

__str__ method. If we print our object, the information displayed is not very useful.

p = Point(1, 2)
print(p)
# <__main__.Point object at 0x102b5a100>

If we define __str__, when using print, it will display whatever we want. It is useful to define this method in your classes, as it helps to see the content of the object.

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __str__(self):
        return f"x={self.x} y={self.y}"

p = Point(1, 2)
print(p) # x=1 y=2

Methods __add__ and __sub__. Imagine you want to add + or subtract - two objects. These methods define the addition and subtraction logic.

  • βž• We define the sum of two points as the sum of the coordinates x on one side and y on the other.
  • βž– We define the subtraction of two points as the subtraction of the coordinates x on one side and y on the other.
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        return Point(self.x - other.x, self.y - other.y)

    def __str__(self):
        return f"x={self.x} y={self.y}"

Now that we have defined both operators, we can use them. If you do not define them, you will get TypeError.

p1 = Point(5, 10) + Point(3, 1)
p2 = Point(-1, 0) - Point(-5, 0)
print(p1) # x=8 y=11
print(p2) # x=4 y=0

Methods __eq__ and __ne__. These two methods allow us to define when two objects are equal or different. We consider two objects equal if their coordinates are equal.

class Point:
    # ...

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __ne__(self, other):
        return not self == other

equal = Point(1, 1) == Point(1, 1)
print(equal)
# True

You can check that they are equal. There are also other methods such as __lt__ or __gt__ that are used to define when one object is less < or greater > than another.

print(Point(1, 1) == Point(1, 1))
# True

Methods __iter__ and __next__. These methods allow us to make a class iterable, that is, we can use it with a for. One defines the iterator object, and the other defines the next number to iterate. We define a class that iterates even numbers up to a limit value.

class Evens:
    def __init__(self, limit):
        self.i = 0
        self.limit = limit

    def __iter__(self):
        return self

    def __next__(self):
        if self.i >= self.limit * 2:
            raise StopIteration
        even = self.i
        self.i += 2
        return even

We can generate the first 5 even numbers as follows.

for i in Evens(5):
    print(i)
# 0, 2, 4, 6, 8

Methods __enter__ and __exit__. They are related to the context manager and we will see them in more detail in the chapter on exceptions. For now, it is enough to know that they allow us to execute an action when entering a block with and another one when exiting. They make a kind of sandwich.

class ContextManager:
    def __enter__(self):
        print("Enter")
        return None

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exit")

with ContextManager() as f:
    print("Inside")

# Enter
# Inside
# Exit

Having seen the most important ones, let us now look at a practical application using the dunder __add__ method seen earlier.

Imagine we have a Currency class that can store values in USD and EUR. A priori, it is not possible to add USD with EUR, since we cannot mix apples and oranges.

However, we can define __add__ so that a conversion to USD is performed. Once both values have been converted, they can be summed.

class Currency:
    rates = {'USD': 1.0, 'EUR': 1.10}

    def __init__(self, currency, amount):
        self.currency = currency
        self.amount = amount

    def convert(self, new_currency):
        if self.currency != new_currency:
            return self.amount * Currency.rates[self.currency] / Currency.rates[new_currency]
        return self.amount

    def __add__(self, other):
        if isinstance(other, Currency):
            amount_usd = self.convert('USD') + other.convert('USD')
            return Currency('USD', amount_usd)
        raise TypeError("Error")

    def __str__(self):
        return f'{self.currency} {self.amount:.2f}'

Now we can add different currencies, as an automatic conversion is performed.

expense1 = Currency('USD', 5.25)
expense2 = Currency('EUR', 7.99)

print(expense1 + expense2)
# USD 14.04

There are other dunder methods that we invite you to review, but we have covered the main ones that will suffice for most of your programs.