PythonMastery

Dunder methods in Python

Make your own class work with +, ==, * and print() by writing dunder (magic) methods. Example: a 2D Vector class.

Dunder methods (short for "double underscore", also called magic methods) are methods with names like __add__. Python calls them for you: a + b runs a.__add__(b), and print(a) uses a.__repr__() when the class has no __str__. Write them, and your objects work with Python's normal operators.

The program

python
import math


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

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __mul__(self, number):
        return Vector(self.x * number, self.y * number)

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

    def __abs__(self):
        return math.hypot(self.x, self.y)


v1 = Vector(1, 2)
v2 = Vector(3, 4)

print(v1 + v2)
print(v1 * 3)
print(v1 + v1 == v1 * 2)
print(abs(v2))
output
Vector(4, 6)
Vector(3, 6)
True
5.0

How it works

Why not __len__ for the length

Some examples use __len__ for the length of a vector. len() is meant for the number of items in a container, and it must return a whole number, so it cannot give 2.236 for Vector(1, 2). Use __len__ for collections:

python
class Playlist:
    def __init__(self, songs):
        self.songs = songs

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

    def __getitem__(self, index):
        return self.songs[index]


mix = Playlist(["Blue Monday", "Heroes", "Hallelujah"])
print(len(mix))
print(mix[0])
for song in mix:
    print("-", song)
output
3
Blue Monday
- Blue Monday
- Heroes
- Hallelujah

__getitem__ makes mix[0] work. It also makes the for loop work: Python calls it with 0, 1, 2 and so on until it gets an IndexError.

Learn the idea: Object-Oriented Programming