Magic (Dunder) Methods in Python
In Python’s object-oriented model, objects can interact with built-in language features such as print(), len(), comparison operators, and more. This interaction is enabled through special methods, commonly called Magic Methods or Dunder Methods (Double-UNDERscore methods).
These methods allow developers to define how objects behave when used with Python’s built-in operations.
For example:
print(obj)→ calls__str__()len(obj)→ calls__len__()obj1 == obj2→ calls__eq__()
Magic methods make custom objects behave like built-in Python types such as lists, strings, or dictionaries.
Understanding Magic (Dunder) Methods
Magic methods are predefined method names in Python that begin and end with double underscores.
Example:
__init__
__str__
__repr__
__len__
__eq__These methods are not meant to be called directly. Instead, Python automatically invokes them when certain operations occur.
Example:
class Demo:
def __str__(self):
return "Demo Object"
d = Demo()
print(d)# internally becomes d.__str__()Why Magic Methods Are Important
Magic methods allow developers to:
- Customize object behavior
- Integrate custom classes with Python’s built-in functions
- Implement operator overloading
- Build intuitive APIs
- Make objects behave like built-in data types
Without magic methods, custom classes would be much less flexible.
1. __str__() — Human-Readable Representation
__str__() returns a human-friendly string representation of an object.
This method is automatically called by:
print(obj)str(obj)format(obj)
The goal of __str__() is to provide a clean and readable description of the object.
Syntax:
def __str__(self):
return "string representation"Example:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Student(Name={self.name}, Age={self.age})"
s = Student("Alice", 22)
print(s)
# output:
# Student(Name=Alice, Age=22)Without __str__()
If __str__() is not implemented:
print(s)
# Output:
# <__main__.Student object at 0x0000018F2D3>This output is not useful for users.
2. __repr__() — Developer-Focused Representation
__repr__() returns the official string representation of an object intended for developers and debugging.
It is used by:
- Python interpreter
- Debugging tools
- repr(obj)
- Interactive shell
The representation should ideally allow recreating the object.
Get Saurabh Gandhi’s stories in your inbox
Join Medium for free to get updates from this writer.
Syntax:
def __repr__(self):
return "representation"Example:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Student('{self.name}', {self.age})"
s = Student("Alice", 22)
repr(s)
# output:
# Student('Alice', 22)__repr__() vs __str__()
Example:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __str__(self):
return f"{self.name} costs ₹{self.price}"
def __repr__(self):
return f"Product('{self.name}', {self.price})"
p = Product("Laptop", 75000)
print(p)
repr(p)3. __len__() — Defining Object Length
__len__() allows an object to define its length.
It is invoked when calling:
len(object)This method must return a non-negative integer.
Example:
class Library:
def __init__(self, books):
self.books = books
def __len__(self):
return len(self.books)
lib = Library(["Python", "ML", "AI"])
print(len(lib))Practical Example — Shopping Cart
class ShoppingCart:
def __init__(self):
self.items = []
def add_item(self, item):
self.items.append(item)
def __len__(self):
return len(self.items)
cart = ShoppingCart()
cart.add_item("Laptop")
cart.add_item("Mouse")
print(len(cart))4. __del__() — Object Destructor
__del__() is a destructor method called when an object is about to be destroyed.
It is used for:
- releasing resources
- closing files
- cleaning up connections
Syntax:
def __del__(self):
# cleanup codeExample:
class FileHandler:
def __init__(self, filename):
self.file = open(filename, "w")
def __del__(self):
print("Closing file")
self.file.close()
f = FileHandler("test.txt")
del fImportant Concept: Garbage Collection
Python uses reference counting and garbage collection to destroy objects.
Therefore, __del__() execution time is not always predictable.
This means:
__del__() is rarely used in production systemsInstead developers use context managers (with statement).
5. __eq__() — Custom Equality Comparison
__eq__() defines how two objects should be compared using ==.
Syntax:
def __eq__(self, other):Example:
class Employee:
def __init__(self, emp_id):
self.emp_id = emp_id
def __eq__(self, other):
return self.emp_id == other.emp_id
e1 = Employee(101)
e2 = Employee(101)
print(e1 == e2)Default Behavior Without __eq__
Without defining __eq__, Python compares memory addresses.
Example:
class Test:
pass
a = Test()
b = Test()
print(a == b)Execution Flow of Magic Methods
User Operation
|
v
Python Built-in Function
|
v
Magic Method TriggeredExample:
print(obj) → obj.__str__()
repr(obj) → obj.__repr__()
len(obj) → obj.__len__()
del obj → obj.__del__()
obj1 == obj2 → obj.__eq__()Questions
- What are magic methods in Python?
- Why are they called “dunder methods”?
- What is the purpose of __str__()?
- Difference between __str__() and __repr__()?
- When does Python call __len__()?
- What happens if __eq__() is not implemented?










