Python Magic Methods
In this page:
class ClassName:
def __init__(self, ...):
# constructor
def __str__(self):
return "text"
def __add__(self, other):
# operator +
What are Magic Methods?
Magic methods (also called dunder methods, for their double underscores like __init__) are special hooks Python calls automatically for built-in operations -- defining __init__ lets you customize object construction, while other dunders let you customize printing, comparison, arithmetic, and more.
Example: What are Magic Methods?
class Point:
def __init__(self, x, y): # __init__ is a magic method Python calls on creation
self.x = x
self.y = y
p = Point(1, 2)
print(p.x, p.y)
Operator Overloading
Defining __add__(self, other) on a class lets the + operator work on your own objects -- write two Vector objects and v1 + v2 calls v1.__add__(v2) behind the scenes, letting you return a new Vector with summed components instead of Python raising a TypeError.
Example: Operator Overloading
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other): # called automatically when using +
return Vector(self.x + other.x, self.y + other.y)
v = Vector(1, 2) + Vector(3, 4) # triggers Vector.__add__
print(v.x, v.y)
Comparison Magic Methods
Overloading __eq__ lets you define what '==' means for your class (like comparing two Point objects by their x/y coordinates rather than by identity), and __lt__ defines '<' so that built-ins like sorted() and min() know how to order your objects.
Example: Comparison Magic Methods
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other): # defines what == means for Point
return self.x == other.x and self.y == other.y
print(Point(1, 2) == Point(1, 2)) # compares coordinates, not identity
Length and Container Methods
Defining __len__ makes len(my_object) work on your custom class, and __getitem__ lets it support square-bracket indexing (my_object[0]) -- together these two are often enough to make a custom class usable anywhere a list or dict would be expected.
Example: Length and Container Methods
class Basket:
def __init__(self, items):
self.items = items
def __len__(self): # makes len(basket) work
return len(self.items)
def __getitem__(self, index): # makes basket[0] work
return self.items[index]
b = Basket(["apple", "banana"])
print(len(b), b[0])
Making Objects Callable
Implementing __call__ lets you invoke an instance directly like a function -- my_object() -- which is useful for objects that wrap some configurable behavior, such as a class that remembers settings and then runs a computation when called.
Example: Making Objects Callable
class Multiplier:
def __init__(self, factor):
self.factor = factor
def __call__(self, x): # lets the instance be called like a function
return x * self.factor
times3 = Multiplier(3)
print(times3(10)) # calls times3.__call__(10)
- Misspelling a magic method, such as
__str_or__lenght__, so Python never calls it and the default behaviour is used. - Returning a non-string from
__str__, which raisesTypeErrorwhen the object is printed. - Defining
__eq__without__hash__, which makes instances unhashable so they cannot be used in sets or as dictionary keys.
Chapter Quiz — Complete all 11 topics to unlock
0/11 topics done
Complete these topics first: