Python Dunder Methods, Demystified πͺ
__init__, __repr__, __add__... they look scary with all those underscores. But once you get the one idea behind them, they stop being magic and start being obvious.
π€ What Does "Dunder" Even Mean?
Dunder = Double UNDERscore.
__init__
β β
double double
underscore underscore
So dunder methods are just methods whose names start and end with __. You'll also hear them called magic methods or special methods β all three names mean the same thing.
Examples: __init__, __repr__, __eq__, __len__, __add__
π‘ Why Do They Exist?
Python already knows what to do with its built-in types:
print(10 + 20) # 30
print(len("hello")) # 5
But now make your own class:
class Money:
def __init__(self, amount):
self.amount = amount
m1 = Money(100)
m2 = Money(200)
print(m1 + m2) # π₯ Error!
Python has no idea what + should mean for two Money objects. Dunder methods are how you teach Python what to do. Define __add__, and suddenly + makes sense for your class too.
The big idea: dunder methods let your custom objects behave like Python's built-in ones.
βοΈ Are They Automatic?
Yes β but you still write them yourself. You just don't call them directly.
| You write | Python actually calls |
|---|---|
a + b |
a.__add__(b) |
len(a) |
a.__len__() |
a == b |
a.__eq__(b) |
print(a) |
uses a.__repr__()
|
You define the dunder method once inside your class. From then on, Python quietly routes the normal syntax to it behind the scenes.
π§ The translation trick: whenever you see a + b, mentally read it as a.__add__(b). Do this for every operator and dunder methods stop feeling magical.
π A Quick Word on self
class Student:
def __init__(self, name):
self.name = name
s1 = Student("Deepika")
When Python runs s1 = Student("Deepika"), it's really doing s1.__init__("Deepika") internally β and inside that method, self is s1. So self.name = name simply means s1.name = "Deepika".
π§° The Core Dunder Methods
__init__ β set up the object
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
Runs automatically when you create an object, to set its starting values.
β οΈ Common myth: "Every class must have
__init__." False β it's optional.class Student: passis perfectly valid Python.
__repr__ β give it a readable identity
Without it:
print(s)
# <__main__.Student object at 0x000001...>
With it:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Student(name='{self.name}', age={self.age})"
print(s)
# Student(name='Deepika', age=21)
Mostly used for clean debugging/logging output.
__eq__ β define what "equal" means
class Student:
def __init__(self, name):
self.name = name
def __eq__(self, other):
return self.name == other.name
s1 = Student("Deepika")
s2 = Student("Deepika")
print(s1 == s2) # True
__len__ β teach len() about your object
class Team:
def __init__(self, members):
self.members = members
def __len__(self):
return len(self.members)
team = Team(["A", "B", "C"])
print(len(team)) # 3
__add__ β define what + means
class Money:
def __init__(self, amount):
self.amount = amount
def __add__(self, other):
return Money(self.amount + other.amount)
m3 = Money(100) + Money(200)
print(m3.amount) # 300
π§© Putting It All Together
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks
def __repr__(self):
return f"Student(name='{self.name}', marks={self.marks})"
def __eq__(self, other):
return self.marks == other.marks
def __len__(self):
return len(self.marks)
def __add__(self, other):
return Student(self.name + " & " + other.name,
self.marks + other.marks)
s1 = Student("Deepika", [90, 95])
s2 = Student("Koushik", [85, 92])
print(s1) # __repr__ β Student(name='Deepika', marks=[90, 95])
print(len(s1)) # __len__ β 2
print(s1 == s2) # __eq__ β False
s3 = s1 + s2 # __add__
π¨ Don't Confuse __main__ with __init__
if __name__ == "__main__":
print("Program started")
__name__ is a special variable and "__main__" is just a special value it can hold β it's not a dunder method. Easy to mix up because both have double underscores, but they're unrelated concepts.
π’ Where This Shows Up in Real Code
| Scenario | Dunder used | Why |
|---|---|---|
| Combining prices in a cart | __add__ |
product1 + product2 reads naturally |
Financial apps (Money, Invoice) |
__add__ |
total = m1 + m2 instead of manual math |
| Shopping cart item count | __len__ |
len(cart) instead of len(cart.items)
|
Debugging a User object |
__repr__ |
print(user) β User(id=101, name='Deepika') instead of a memory address |
This isn't just interview trivia β it's how real Python libraries (like datetime, pandas, or pathlib) make objects feel native to the language.
π― Cheat-Sheet Answers
| Question | Short Answer |
|---|---|
| What are dunder methods? | Special methods with double-underscore names that define how your objects respond to built-in Python operations |
| Do we call them directly? | Usually no β normal syntax (+, len(), ==) triggers them automatically |
Do all classes need __init__? |
No, it's optional β only needed to initialize attributes |
| Why called "magic methods"? | Because Python invokes them behind the scenes, without an explicit call |
π§ One Picture to Remember
YOUR OBJECT
β
"How should I behave?"
βββββββββββββΌβββββββββββββ
β β β
+ == len()
β β β
__add__ __eq__ __len__
object created β __init__
object printed β __repr__
Golden rule: Dunder methods are the mechanism Python uses to let your custom objects participate naturally in its built-in operations.
Top comments (0)