Home Tutorials OOP

OOP

The __call__ Method: Making Python Objects Behave Like Functions

Pyford Notes July 6, 2026 7 min read
Key points
  • obj() calls obj.__class__.__call__(obj), so any object whose class defines __call__ can be used with function-call syntax.
  • A callable class keeps state between calls in ordinary instance attributes, which is often clearer than a closure juggling nonlocal variables.
  • Class-based decorators implement __call__ to wrap the decorated function, and often __init__ to accept decorator arguments.
  • The built-in callable(obj) checks for __call__ without invoking it, useful for validating that a parameter is a function-like object.

Any object with __call__ can be called

Parentheses after an object — obj(args) — are syntax sugar for type(obj).__call__(obj, args). Functions are callable because the function type implements __call__; nothing stops any other class from implementing it too, at which point instances of that class can be invoked exactly like a function, while still carrying all the state and methods a normal object has:

class Multiplier:
    def __init__(self, factor):
        self.factor = factor

    def __call__(self, value):
        return value * self.factor

double = Multiplier(2)
triple = Multiplier(3)

print(double(21))   # 42 -- double is an instance, called like a function
print(triple(10))   # 30

print(callable(double))   # True

double here is a fully ordinary object — it has a factor attribute, it could have other methods, it could be pickled — it just also happens to be invokable with ().

Why a class beats a closure for stateful callables

A closure over nonlocal variables can achieve something similar, but a callable class scales better once the state has more than one or two fields, or needs to be inspected and modified from outside:

# Closure version: state hidden inside the closure, awkward to inspect or reset
def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

# Class version: state is a normal, inspectable, resettable attribute
class Counter:
    def __init__(self, start=0):
        self.count = start

    def __call__(self):
        self.count += 1
        return self.count

    def reset(self):
        self.count = 0

c = Counter()
print(c(), c(), c())   # 1 2 3
c.reset()
print(c.count)          # 0 -- directly readable, unlike the closure's hidden count

The class version also supports adding more methods (reset above), subclassing, and straightforward unit testing by inspecting c.count directly, none of which a bare closure offers without extra plumbing.

Class-based decorators built on __call__

A common, practical use of __call__ is writing decorators as classes instead of nested functions, which becomes especially convenient once the decorator itself needs configuration arguments:

import functools

class retry:
    def __init__(self, times=3):
        self.times = times

    def __call__(self, func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            last_exc = None
            for attempt in range(self.times):
                try:
                    return func(*args, **kwargs)
                except Exception as exc:
                    last_exc = exc
            raise last_exc
        return wrapper

@retry(times=5)
def flaky_request():
    ...

# Equivalent to: flaky_request = retry(times=5)(flaky_request)
# retry(times=5) constructs an instance; calling that instance with flaky_request
# is what __call__ handles, returning the wrapped function.

Here @retry(times=5) first constructs a retry instance via __init__, then Python calls that instance with the decorated function as its argument — which is exactly the job __call__ does, returning the final wrapped function.

Checking callability with callable()

The built-in callable(obj) reports whether type(obj) defines __call__, without actually invoking anything. It's the right way to validate that a parameter someone passed in behaves like a function, regardless of whether it's an actual function, a lambda, a bound method, or a class instance implementing __call__:

def apply_twice(func, value):
    if not callable(func):
        raise TypeError(f"expected a callable, got {type(func).__name__}")
    return func(func(value))

print(apply_twice(double, 5))   # 20 -- Multiplier(2) instance from earlier works fine

Where this shows up in real libraries

functools.partial objects are callable, implemented in C but conceptually identical to the Multiplier example. PyTorch and other machine-learning libraries make neural network layers callable so that layer(input_tensor) runs the forward pass while the layer object itself still holds its trained weights as ordinary attributes. Pytest fixtures and Click command objects lean on the same pattern. In all these cases the motivation is the same: something needs to look and behave like a plain function call at the point of use, while carrying configuration or state that a bare function has nowhere to put. The data model documentation for __call__ covers the exact signature Python expects.