CodeNebula
Python🔧Core Languagebeginner

Dunder (Magic) Methods

Python · Core Language · Run with python3

Explanation

Dunder methods (`__method__`) let classes integrate with Python's built-in operators and protocols. `__repr__` / `__str__` control string representation. `__len__`, `__getitem__`, `__setitem__`, `__iter__` implement the sequence and mapping protocols. `__enter__` / `__exit__` enable the `with` statement. `__eq__`, `__lt__`, `__hash__` control equality and hashing. `__call__` makes instances callable.

Real-World Scenario

A `Matrix` class implementing `__add__`, `__mul__`, `__getitem__`, and `__repr__` works with `+`, `*`, `[]`, and `print()` — the same interface as built-in numeric types. This is how NumPy arrays feel like "native" objects. ```python class Vector: def __init__(self, *components): self._data = list(components) def __repr__(self): return f"Vector{tuple(self._data)}" def __len__(self): return len(self._data) def __getitem__(self, i): return self._data[i] def __add__(self, other): return Vector(*(a + b for a, b in zip(self, other))) def __mul__(self, scalar): return Vector(*(x * scalar for x in self)) def __eq__(self, other): return self._data == list(other) v1 = Vector(1, 2, 3) v2 = Vector(4, 5, 6) print(v1 + v2) # Vector(5, 7, 9) print(v1 * 3) # Vector(3, 6, 9) print(len(v1)) # 3 print(v1[1]) # 2 ```

Quick Snippet

snippet.py
class Vector:
    def __init__(self, *components):
        self._data = list(components)

    def __repr__(self): return f"Vector{tuple(self._data)}"
    def __len__(self):  return len(self._data)
    def __getitem__(self, i): return self._data[i]
    def __add__(self, other): return Vector(*(a + b for a, b in zip(self, other)))
    def __mul__(self, scalar): return Vector(*(x * scalar for x in self))
    def __eq__(self, other):  return self._data == list(other)

v1 = Vector(1, 2, 3)
v2 = Vector(4, 5, 6)
print(v1 + v2)    # Vector(5, 7, 9)
print(v1 * 3)     # Vector(3, 6, 9)
print(len(v1))    # 3
print(v1[1])      # 2

Full Example

dunder_methods.py
# Compile: python3 dunder_methods.py
# Output:
# Vector(5, 7, 9)
# Vector(3, 6, 9)
# 3
# 2

class Vector:
    def __init__(self, *components):
        self._data = list(components)

    def __repr__(self): return f"Vector{tuple(self._data)}"
    def __len__(self):  return len(self._data)
    def __getitem__(self, i): return self._data[i]
    def __add__(self, other): return Vector(*(a + b for a, b in zip(self, other)))
    def __mul__(self, scalar): return Vector(*(x * scalar for x in self))
    def __eq__(self, other): return self._data == list(other)
    def __iter__(self): return iter(self._data)
    def __contains__(self, item): return item in self._data

v1 = Vector(1, 2, 3)
v2 = Vector(4, 5, 6)
print(v1 + v2)
print(v1 * 3)
print(len(v1))
print(v1[1])
print(2 in v1)   # True
print(v1 == Vector(1, 2, 3))  # True

# __call__ — makes instances callable
class Multiplier:
    def __init__(self, factor): self.factor = factor
    def __call__(self, x): return x * self.factor

double = Multiplier(2)
print(double(5))   # 10
print(double(10))  # 20
Run command
python3 dunder_methods.py