When defining a class in Python, you often see methods surrounded by double underscores (e.g., __init__). These are called Special Methods or Magic Methods.
By defining special methods, you can make your custom classes behave like Python’s built-in types (such as lists or numbers). For example, you can customize how objects behave when added together with + or how they are displayed with print().
This article explains the roles and implementation of representative special methods.
What are Special Methods?
Special methods follow the naming convention __method_name__. Programmers rarely call them directly (like obj.__str__()). Instead, they are automatically called by Python internals when specific syntax or built-in functions are executed.
| Syntax / Function | Special Method Called |
| Instance creation | __init__ |
print(obj) / str(obj) | __str__ |
repr(obj) | __repr__ |
obj1 + obj2 | __add__ |
obj1 == obj2 | __eq__ |
Basic Special Methods
First, let’s look at the basic methods that are almost essential when defining a class. As an example, we will create a Coordinate class representing 2D coordinates.
1. Initialization: __init__
Called when an instance is generated. It performs initial settings for attributes (Constructor).
2. String Representation: __str__ and __repr__
Defines the string representation of the object.
__str__: For users. Used in theprint()function.__repr__: For developers. Used during debugging or when displayed inside a list.
class Coordinate:
def __init__(self, x, y):
"""Initialization method"""
self.x = x
self.y = y
def __str__(self):
"""String called by print(), etc."""
return f"Coord({self.x}, {self.y})"
def __repr__(self):
"""Strict string for developers"""
return f"Coordinate({self.x}, {self.y})"
# Instantiation (__init__ is called)
point = Coordinate(10, 20)
# String representation (__str__ is called)
print(f"Output: {point}")
# Display inside a list (__repr__ is called)
points_list = [point, Coordinate(5, 5)]
print(f"List: {points_list}")
Output:
Output: Coord(10, 20)
List: [Coordinate(10, 20), Coordinate(5, 5)]
Customizing Operators (Operator Overloading)
The true power of special methods is the ability to add features like arithmetic operations to custom classes.
3. Addition: __add__
Defines the behavior when the + operator is used. Here, we implement the process of adding two coordinates (vector addition).
4. Equality: __eq__
Defines the behavior when the == operator is used. By default, it checks “is it the exact same object (memory address)?”, but here we change it to consider them equal if “the x and y values are the same.”
class Coordinate:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"({self.x}, {self.y})"
def __add__(self, other):
"""
Definition for + operator
Returns a new instance with the sum of x and y from self and other
"""
new_x = self.x + other.x
new_y = self.y + other.y
return Coordinate(new_x, new_y)
def __eq__(self, other):
"""
Definition for == operator
Returns True if values are the same
"""
return self.x == other.x and self.y == other.y
# Create two coordinates
p1 = Coordinate(10, 20)
p2 = Coordinate(30, 40)
p3 = Coordinate(10, 20)
# Addition (__add__ is called)
p_sum = p1 + p2
print(f"Addition Result: {p_sum}")
# Equality check (__eq__ is called)
print(f"p1 == p2: {p1 == p2}")
print(f"p1 == p3: {p1 == p3}")
Output:
Addition Result: (40, 60)
p1 == p2: False
p1 == p3: True
By defining __add__, intuitive notation like p1 + p2 became possible.
Summary
By defining special methods (magic methods), you can integrate custom classes into Python’s language features.
__init__: Initialization process.__str__/__repr__: String representation.__add__: Definition of the+operator.__eq__: Definition of the==operator.
Implementing these appropriately allows you to design classes that are easy to use and intuitive.
