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
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))
Vector(4, 6) Vector(3, 6) True 5.0
How it works
__repr__returns the text thatprint()and the console show for the object.__add__runs for+and__mul__runs for*. Each one returns a newVectorand leaves the original vectors unchanged, the same way2 + 3does not change 2.- Without
__eq__,==checks whether two names point to the same object, so two equal vectors would compare asFalse. __abs__runs forabs(). For a vector, that is its length:math.hypot(3, 4)is the square root of 3² + 4², which is 5.0.
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:
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)
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.