Courses/Python/Operator Overloading & Custom Behaviours

    Lesson 29 โ€ข Advanced

    Operator Overloading & Custom Behaviours

    Master operator overloading to make your classes behave like built-in types. Learn the techniques used by NumPy, PyTorch, Pandas, and SQLAlchemy to create intuitive, powerful APIs through custom operator behaviors.

    ๐Ÿ”ฅ Operator Overloading & Custom Behaviours

    Operator overloading lets your classes behave like built-in types:

    • โœ” Numbers
    • โœ” Strings
    • โœ” Lists
    • โœ” Dictionaries
    • โœ” Booleans
    • โœ” Comparisons
    • โœ” Arithmetic
    • โœ” Indexing
    • โœ” Iteration

    Real frameworks rely on this heavily:

    • NumPy โ†’ vector arithmetic
    • PyTorch โ†’ tensor operations
    • SQLAlchemy โ†’ query expressions
    • Pandas โ†’ Series/DataFrame math
    • Pathlib โ†’ path addition
    • Datetime โ†’ duration arithmetic

    If you want to build professional-grade classes, operator overloading is mandatory.

    โš™๏ธ 1. Why Operator Overloading Exists

    Python allows classes to define behavior for:

    + - * / // % **

    == != < <= > >=

    [] indexing

    in membership

    len(), bool(), iter(), call(), with

    You override these by implementing "magic methods" such as:

    • __add__, __sub__, __mul__, __truediv__
    • __eq__, __lt__
    • __getitem__, __setitem__
    • __contains__, __len__, __bool__, __call__

    These make your objects feel native and intuitive.

    ๐Ÿ”ข 2. Overloading Arithmetic Operators

    Let's build a simple 2D vector class with all arithmetic operators:

    Vector Arithmetic

    Try it Yourself ยป
    Python
    class Vec:
        def __init__(self, x, y):
            self.x = x
            self.y = y
        
        def __repr__(self):
            return f"Vec({self.x}, {self.y})"
        
        # Addition โ†’ __add__
        def __add__(self, other):
            return Vec(self.x + other.x, self.y + other.y)
        
        # Subtraction โ†’ __sub__
        def __sub__(self, other):
            return Vec(self.x - other.x, self.y - other.y)
        
        # Multiplication โ†’ __mul__ (scalar)
        def __mul__(self, scalar):
            return Vec(self.x * scalar, self.
    ...

    ๐Ÿง  3. Overloading String & Representation Functions

    Two methods control how your objects appear in logs, REPLs, and print statements:

    __repr__ and __str__

    Try it Yourself ยป
    Python
    class Vec:
        def __init__(self, x, y):
            self.x = x
            self.y = y
        
        # Developer view (unambiguous)
        def __repr__(self):
            return f"Vec({self.x}, {self.y})"
        
        # User-friendly view
        def __str__(self):
            return f"({self.x}, {self.y})"
    
    v = Vec(10, 20)
    
    # __repr__ is used by repr() and in collections
    print(f"repr(v): {repr(v)}")
    
    # __str__ is used by str() and print()
    print(f"str(v): {str(v)}")
    print(f"print(v):", v)
    
    # In a list, __repr__ is used
    print(f
    ...

    ๐Ÿงฉ 4. Comparison Operators

    To support sorting, filtering, searching, or ordering, implement:

    • __eq__ โ€” ==
    • __ne__ โ€” !=
    • __lt__ โ€” <
    • __le__ โ€” <=
    • __gt__ โ€” >
    • __ge__ โ€” >=

    Comparison Operators

    Try it Yourself ยป
    Python
    class Vec:
        def __init__(self, x, y):
            self.x = x
            self.y = y
        
        def __repr__(self):
            return f"Vec({self.x}, {self.y})"
        
        def magnitude(self):
            return (self.x**2 + self.y**2) ** 0.5
        
        # Compare by magnitude
        def __lt__(self, other):
            return self.magnitude() < other.magnitude()
        
        def __eq__(self, other):
            return self.x == other.x and self.y == other.y
    
    # Test comparisons
    v1 = Vec(3, 4)   # magnitude = 5
    v2 = Vec(1, 1)   # 
    ...

    ๐Ÿ“ฆ 5. Overloading Indexing & Slicing

    Indexing and Slicing

    Try it Yourself ยป
    Python
    class Vec:
        def __init__(self, x, y):
            self.x = x
            self.y = y
        
        def __repr__(self):
            return f"Vec({self.x}, {self.y})"
        
        def __getitem__(self, idx):
            if isinstance(idx, slice):
                return (self.x, self.y)[idx]
            if idx == 0:
                return self.x
            if idx == 1:
                return self.y
            raise IndexError("Vec only has 2 dimensions")
        
        def __setitem__(self, idx, value):
            if idx == 0:
                self.x = val
    ...

    ๐Ÿ”„ 6-7. Membership & Iteration

    __contains__ and __iter__

    Try it Yourself ยป
    Python
    class Vec:
        def __init__(self, x, y):
            self.x = x
            self.y = y
        
        def __repr__(self):
            return f"Vec({self.x}, {self.y})"
        
        # Membership test (in)
        def __contains__(self, val):
            return val == self.x or val == self.y
        
        # Make iterable
        def __iter__(self):
            yield self.x
            yield self.y
        
        # Length
        def __len__(self):
            return 2
    
    # Test
    v = Vec(10, 20)
    
    # Membership
    print(f"v = {v}")
    print(f"10 in v: {10 in v}")
    print
    ...

    ๐Ÿ”ฅ 8-9. Boolean & Call Behavior

    __bool__ and __call__

    Try it Yourself ยป
    Python
    class Vec:
        def __init__(self, x, y):
            self.x = x
            self.y = y
        
        def __repr__(self):
            return f"Vec({self.x}, {self.y})"
        
        # Boolean behavior
        def __bool__(self):
            return bool(self.x or self.y)
        
        # Make callable
        def __call__(self, scale):
            return Vec(self.x * scale, self.y * scale)
    
    # Test boolean
    zero = Vec(0, 0)
    nonzero = Vec(1, 2)
    
    print(f"bool({zero}): {bool(zero)}")
    print(f"bool({nonzero}): {bool(nonzero)}")
    
    if nonzero:
        pr
    ...

    โšก 10-11. Reverse & Augmented Operators

    Reverse and Augmented Operators

    Try it Yourself ยป
    Python
    class Vec:
        def __init__(self, x, y):
            self.x = x
            self.y = y
        
        def __repr__(self):
            return f"Vec({self.x}, {self.y})"
        
        # Regular add
        def __add__(self, other):
            if isinstance(other, Vec):
                return Vec(self.x + other.x, self.y + other.y)
            return Vec(self.x + other, self.y + other)
        
        # Reverse add: when left operand doesn't support +
        def __radd__(self, other):
            return self.__add__(other)
        
        # Augmented add: 
    ...

    ๐ŸŽฏ 12-13. Rich Container & Matrix Indexing

    Container Behaviors

    Try it Yourself ยป
    Python
    class Matrix:
        def __init__(self, rows):
            self.data = rows
        
        def __repr__(self):
            return f"Matrix({self.data})"
        
        def __len__(self):
            return len(self.data)
        
        def __iter__(self):
            for row in self.data:
                yield row
        
        def __contains__(self, item):
            return any(item in row for row in self.data)
        
        # Multi-dimensional indexing like NumPy
        def __getitem__(self, key):
            if isinstance(key, tuple):
                row, 
    ...

    ๐ŸŒ€ 14-16. Bitwise & Context Operators

    Bitwise and Context Managers

    Try it Yourself ยป
    Python
    class Permission:
        """Bitwise operators for permission flags."""
        def __init__(self, value):
            self.value = value
        
        def __repr__(self):
            return f"Permission({self.value})"
        
        def __or__(self, other):
            return Permission(self.value | other.value)
        
        def __and__(self, other):
            return Permission(self.value & other.value)
        
        def __xor__(self, other):
            return Permission(self.value ^ other.value)
        
        def __invert__(self):
            ret
    ...

    ๐Ÿ‘‘ 17-19. DSL Building with Operators

    Massive libraries rely on operator overloads to create readable "fake languages":

    • SQLAlchemy: User.age > 18
    • PyTorch: x = tensor * 3 + tensor2
    • Pandas: df["col"] + df["other"]
    • Pathlib: path = Path("home") / "user"
    Python
    # Simple expression DSL like SQLAlchemy
    class Column:
        def __init__(self, name):
            self.name = name
        
        def __gt__(self, value):
            return f"{self.name} > {value}"
        
        def __lt__(self, value):
            return f"{self.name} < {value}"
        
        def __eq__(self, value):
            return f"{self.name} = '{value}'"
    
    # SQLAlchemy-style expressions
    User = type('User', (), {
        'age': Column('age'),
        'name': Column('name'),
        'active': Column('active')
    })()
    
    query1 = User.age 
    ...

    ๐Ÿงฉ 20-22. Attribute Access & Delegation

    Attribute Access Control

    Try it Yourself ยป
    Python
    class Proxy:
        """Intercept all attribute access."""
        def __init__(self, target):
            object.__setattr__(self, '_target', target)
        
        def __getattr__(self, name):
            print(f"Getting: {name}")
            return getattr(self._target, name)
        
        def __setattr__(self, name, value):
            if name == '_target':
                object.__setattr__(self, name, value)
            else:
                print(f"Setting: {name} = {value}")
                setattr(self._target, name, value)
    
    class Data:
    ...

    ๐Ÿ”ฅ 23-24. Complete Mathematical System

    Complete Vector Class

    Try it Yourself ยป
    Python
    class Vec:
        """Fully overloaded 2D vector."""
        __slots__ = ('x', 'y', '__weakref__')
        
        def __init__(self, x, y):
            self.x = x
            self.y = y
        
        def __repr__(self):
            return f"Vec({self.x}, {self.y})"
        
        # Arithmetic
        def __add__(self, other):
            if isinstance(other, Vec):
                return Vec(self.x + other.x, self.y + other.y)
            return Vec(self.x + other, self.y + other)
        
        __radd__ = __add__
        
        def __sub__(self, other):
         
    ...

    ๐Ÿงต 25-27. Immutable vs Mutable Design

    Immutable vs Mutable

    Try it Yourself ยป
    Python
    # Immutable (returns new object)
    class ImmutableVec:
        __slots__ = ('_x', '_y')
        
        def __init__(self, x, y):
            object.__setattr__(self, '_x', x)
            object.__setattr__(self, '_y', y)
        
        @property
        def x(self):
            return self._x
        
        @property
        def y(self):
            return self._y
        
        def __repr__(self):
            return f"ImmutableVec({self._x}, {self._y})"
        
        def __add__(self, other):
            return ImmutableVec(self._x + other._x, self._y + other.
    ...

    โšก 28-30. Computation Graphs & Best Practices

    Computation Graph Pattern

    Try it Yourself ยป
    Python
    # TensorFlow/PyTorch-style computation graph
    class Node:
        def __add__(self, other):
            return Add(self, other)
        
        def __mul__(self, other):
            return Mul(self, other)
    
    class Var(Node):
        def __init__(self, name, value=None):
            self.name = name
            self.value = value
        
        def __repr__(self):
            return self.name
    
    class Add(Node):
        def __init__(self, a, b):
            self.a = a
            self.b = b
        
        def __repr__(self):
            return f"({self.a} + {sel
    ...

    ๐ŸŽฏ Summary โ€” You Now Understand the Full Python Operator Model

    You now understand:

    • โœ” Operator dispatching
    • โœ” Delegation
    • โœ” Emulating built-ins
    • โœ” Full numerical operator suite
    • โœ” Boolean overloading
    • โœ” Callable objects
    • โœ” Immutable vs mutable design
    • โœ” DSL construction
    • โœ” Computation graph building
    • โœ” Best practices for errors
    • โœ” Weakref integration

    This puts you at a framework engineer level (the people who build NumPy/Pandas/PyTorch, not just use them).

    ๐Ÿ“‹ Quick Reference โ€” Operator Overloading

    MethodOperator
    __add__(self, other)a + b
    __eq__(self, other)a == b
    __lt__(self, other)a < b (enables sorting)
    __mul__(self, other)a * b
    @functools.total_orderingAuto-fill comparison methods

    ๐ŸŽ‰ Great work! You've completed this lesson.

    Your classes can now support arithmetic, comparisons, and other operators โ€” making your APIs as intuitive as built-in Python types.

    Up next: Mixins โ€” compose reusable behaviour across multiple classes without deep inheritance chains.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy Policy โ€ข Terms of Service