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}")(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)]))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)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
- Give a
Bookclass a__str__that prints the title and the author. - Write a
Vectorclass with__add__,__sub__and__repr__. - Add
__lt__to aStudentclass so a list of students can be sorted by marks. - Rewrite
Pointas a data class and print one.