Theme: Operators are just syntactic sugar for dunder methods. Understanding how Python routes
NotImplementedthrough the execution engine allows you to make custom objects interact seamlessly with built-in types.
| Operator | Dunder Method | Fallback | Rule |
|---|---|---|---|
a + b |
a.__add__(b) |
b.__radd__(a) |
Must return a new object. |
a * b |
a.__mul__(b) |
b.__rmul__(a) |
Must return a new object. |
a += b |
a.__iadd__(b) |
a = a.__add__(b) |
Must mutate and return self. |
a == b |
a.__eq__(b) |
b.__eq__(a) |
Return NotImplemented if types mismatch. |
examples.py— Demonstrating__add__and duck typing__radd__to allowTuple + Vector.exercises.py— The fatal__iadd__trap (overwriting an object withNone).mini_project.py— A 3D Matrix pipeline proving professional operator overloading safely.benchmarks.py— Proves that relying on__add__for augmented assignment (+=) is ~3.5x slower than implementing__iadd__.notes.md— The operator dispatch workflow and immutability rules.pitfalls.md— TheNotImplementedErrorcrash and mutatingselfinside__add__.interview_questions.md— L3 to L6 interview prep.architecture_notes.md— The CPythonPyNumberMethodsstruct and type slots.
# Rule 1: Standard operators MUST return a new object.
def __add__(self, other):
return Vector(self.x + other.x)
# Rule 2: In-place operators MUST mutate and return self.
def __iadd__(self, other):
self.x += other.x
return self # Fatal bug if forgotten!
# Rule 3: Return NotImplemented when you don't recognize the other operand.
def __mul__(self, scalar):
if not isinstance(scalar, (int, float)):
return NotImplemented
return Vector(self.x * scalar)Reference: Fluent Python 2nd ed., Chapter 16 — pages 589–632