Shiklo Tools
PDF40
Image20
Calculators & Converters25
Text & Writing13
Developer26
Video14
Audio14
Document14
Data & Spreadsheet12
Web & SEO9
OCR & Scanning5
Archive & File12
Security & Privacy23
Health & Medical29
QR & Barcode5

Python Special Methods

Methods whose names start and end with two underscores, such as __init__, are special methods, often called dunder methods (from "double underscore"). Python calls them automatically for built-in operations: print(obj) calls __str__, a + b calls __add__, len(x) calls __len__. Writing them lets your own classes behave like built-in types.

Text for people and for programmers

Without special methods, printing an object shows only its class and a memory address. __str__ gives a friendly text for print, and __repr__ an exact text for programmers, shown in the interactive interpreter and inside lists:

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

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

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

p = Point(3, 4)
print(p)
print([p, Point(0, 0)])
print(f"p is {p}, repr {p!r}")
Output
(3, 4)
[Point(3, 4), Point(0, 0)]
p is (3, 4), repr Point(3, 4)

A good __repr__ looks like the code that creates the object.

Comparing and calculating

class Money:
    def __init__(self, rupees):
        self.rupees = rupees
    def __repr__(self):
        return f"Money({self.rupees})"
    def __add__(self, other):
        return Money(self.rupees + other.rupees)
    def __mul__(self, n):
        return Money(self.rupees * n)
    def __eq__(self, other):
        return self.rupees == other.rupees
    def __lt__(self, other):
        return self.rupees < other.rupees

a, b = Money(250), Money(100)
print(a + b, a * 3)
print(a == Money(250), a < b)
print(sorted([a, b, Money(175)]))
Output
Money(350) Money(750)
True False
[Money(100), Money(175), Money(250)]

__eq__ decides what == means; without it, two objects are equal only if they are the very same object. With __lt__ (less than), sorted, min and max can order your objects.

Behaving like a collection

__len__ makes len work, __getitem__ makes indexing and for loops work, and __contains__ makes in work:

class Playlist:
    def __init__(self, *songs):
        self.songs = list(songs)
    def __len__(self):
        return len(self.songs)
    def __getitem__(self, i):
        return self.songs[i]
    def __contains__(self, song):
        return song in self.songs

mix = Playlist("Song A", "Song B", "Song C")
print(len(mix), mix[0], "Song B" in mix)
for song in mix:
    print("-", song)
Output
3 Song A True
- Song A
- Song B
- Song C

Data classes

For classes that mainly hold data, the dataclasses module writes __init__, __repr__ and __eq__ for you: put @dataclass above the class and list the fields with their types, such as name: str. Data classes save a lot of typing and are a good default for simple records such as a point, a product or a student.

Practice exercises

  1. Give a Book class a __str__ that prints the title and the author.
  2. Write a Vector class with __add__, __sub__ and __repr__.
  3. Add __lt__ to a Student class so a list of students can be sorted by marks.
  4. Rewrite Point as a data class and print one.