Skip to lesson
Python for JS Developers

OOPLesson 3 of 3

Dunder Methods

3 min

Dunder (Double UNDERscore) methods let you hook into Python's built-in operations. Want your class to support the + operator? Define __add__. Want print() to show something useful? Define __str__. Want len() to work? Define __len__. This is operator overloading, and it is one of Python's most powerful features.

JS has a tiny version of this with Symbol.iterator, toString, and valueOf, but Python takes it much further. You can overload every arithmetic operator, every comparison, indexing, iteration, even the () call syntax. A class with __call__ becomes callable like a function.

The practical result: your custom objects can behave exactly like built-in types. Users of your class do not need to learn special method names; they use +, -, ==, for loops, and print() as they would with any built-in.

Two rules keep operator methods well behaved. First, if the other operand is a type you do not support, return NotImplemented (do not raise); Python then tries the other operand's method or raises a clean TypeError. Second, defining __eq__ sets __hash__ to None, which makes instances unhashable. If your objects must go in sets or be dict keys, define __hash__ too (or use a frozen dataclass).

Quick reference

JavaScriptPythonNote
toString()__str__ / __repr____str__ for users, __repr__ for devs
Cannot overload +__add__(self, other)Full operator overloading
Cannot overload ==__eq__(self, other)Comparison operators
[Symbol.iterator]()__iter__ / __next__Iterator protocol
No equivalent__len__Support len()
Proxy get trap (clunky)__getitem__Support obj[key]
No equivalent__call__Make object callable

Side by side

JavaScript
// JavaScript - limited overloading
class Vector {
  constructor(x, y) { this.x = x; this.y = y; }
  add(other) {
    return new Vector(this.x+other.x, this.y+other.y);
  }
  toString() { return "("+this.x+", "+this.y+")"; }
}
// v1 + v2 <- does NOT work in JS!
Python
# Python - full operator overloading
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"
    def __str__(self):
        return f"({self.x}, {self.y})"
    def __add__(self, other):     # +
        if not isinstance(other, Vector):
            return NotImplemented
        return Vector(self.x+other.x, self.y+other.y)
    def __mul__(self, s):         # *
        return Vector(self.x*s, self.y*s)
    def __eq__(self, other):      # ==
        if not isinstance(other, Vector):
            return NotImplemented
        return self.x==other.x and self.y==other.y
    def __len__(self):            # len()
        return 2
    def __iter__(self):           # for loop / unpacking
        yield self.x
        yield self.y

v1 = Vector(1, 2)
v3 = v1 + Vector(3, 4)  # Works! -> (4, 6)
x, y = v3               # uses __iter__

Exercise

Real Python, running in your browser

Write a Money class that supports these operations:

Starter code
m1 = Money(100, "USD")
m2 = Money(50, "USD")

m1 + m2   -> Money(150, "USD")
m1 - m2   -> Money(50, "USD")
m1 * 3    -> Money(300, "USD")
print(m1) -> "100.00 USD"
m1 == Money(100, "USD")  -> True
m1 > m2   -> True
m1 + Money(10, "EUR")   -> ValueError!

(Plain numbers are fine here; real apps should use
decimal.Decimal or integer cents.)

Ctrl + Enter runCtrl + Shift + Enter checkTab indentEsc then Tab to leave the editorCtrl + / comment