Magic methods (also known as dunder methods, for “double underscore”) are special methods in Python that enable operator overloading and hook into built-in behaviors.

🔹 __init__
: Object Constructor
Called when an object is created.
class Dog:
def __init__(self, name):
self.name = name
dog = Dog("Fido")
print(dog.name) # Fido
🔹 __str__
and __repr__
: String Representations
class Dog:
def __init__(self, name): self.name = name
def __str__(self): return f"Dog named {self.name}"
def __repr__(self): return f"Dog({self.name!r})"
dog = Dog("Fido")
print(dog) # Dog named Fido
print(repr(dog)) # Dog('Fido')
🔹 __len__
: Length of Object
Used by len(obj)
class Basket:
def __init__(self, items): self.items = items
def __len__(self): return len(self.items)
b = Basket(["apple", "banana"])
print(len(b)) # 2
🔹 __getitem__
, __setitem__
, __delitem__
: Indexing
class Container:
def __init__(self): self.data = {}
def __getitem__(self, key): return self.data[key]
def __setitem__(self, key, value): self.data[key] = value
def __delitem__(self, key): del self.data[key]
c = Container()
c['x'] = 42
print(c['x']) # 42
del c['x']
🔹 __call__
: Makes Object Callable Like a Function
class Greeter:
def __call__(self, name): return f"Hello, {name}!"
greet = Greeter()
print(greet("Alice")) # Hello, Alice!
🔹 __eq__
, __lt__
, etc.: Comparisons
class Point:
def __init__(self, x): self.x = x
def __eq__(self, other): return self.x == other.x
def __lt__(self, other): return self.x < other.x
a = Point(1)
b = Point(2)
print(a == b) # False
print(a < b) # True
🔹 __add__
, __sub__
, __mul__
, etc.: Operator Overloading
class Vector:
def __init__(self, x): self.x = x
def __add__(self, other): return Vector(self.x + other.x)
def __repr__(self): return f"Vector({self.x})"
v1 = Vector(3)
v2 = Vector(4)
print(v1 + v2) # Vector(7)
🔹 __enter__
and __exit__
: Context Manager (with
)
class FileManager:
def __enter__(self):
print("Open resource")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Close resource")
with FileManager():
print("Using resource")
# Output:
# Open resource
# Using resource
# Close resource
🔹 __getattr__
and __setattr__
: Dynamic Attribute Access
class Dynamic:
def __getattr__(self, name): return f"No attribute '{name}'"
def __setattr__(self, name, value):
print(f"Setting {name} = {value}")
super().__setattr__(name, value)
d = Dynamic()
print(d.foo) # No attribute 'foo'
d.x = 10 # Setting x = 10
🔹 __del__
: Object Destructor (⚠️ rarely needed)
class Temp:
def __del__(self):
print("Object destroyed")
t = Temp()
del t # Object destroyed (maybe)
🔹 __new__
: Call the constructor (⚠️ rarely needed)
__new__
is called before __init__
and is responsible for actually creating the instance of the class. It’s most useful when:
- You’re subclassing immutable types (
int
,str
,tuple
) - You need to control the instantiation process (e.g., singleton pattern)
Subclassing immutable types:
class MyInt(int):
def __new__(cls, value):
return super().__new__(cls, value + 1)
x = MyInt(5)
print(x) # 6
Singleton design pattern:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
a = Singleton()
b = Singleton()
print(a is b) # True
__new__ vs __init__
_new__ | __init__ |
Creates the object (allocates memory) | Initializes the object after it’s created |
First method called during instantiation | Second method called |
Used for immutable types and special creation | Used for setting attributes |
Cheatsheet of magic methods
Purpose | Method |
Constructor | __new__, __init__ |
String display | __str__ , __repr__ |
Collections | __iter__ , __next__ |
Operators | __add__ , __eq__ , etc. |
Iteration | __iter__ , __next__ |
Context manager | __enter__ , __exit__ |
Attribute access | __getattr__ , __setattr__ |

Early in my career, I specialized in the Python language. Python has been a constant in my professional life for over 10 years now. In 2018, I moved to London where I worked at companies of various sizes as a Python developer for five years. In parallel, I developed my activity as a Mentor, to which I now dedicate myself full-time.