skip to content

What does defining `__call__` on a Python class let you do with its instances?

level: juniorimportance: should knowfreq 45%

answer

  1. An object used with parentheses
  2. Functions are objects too
  3. Alternative to a stateful closure
  4. One builtin reports whether it works

basics

~10 s

It makes the instances callable: writing obj(args) runs type(obj).__call__(obj, args). The object behaves like a function while keeping its own state in ordinary attributes, and callable(obj) reports True.

solid answer

~40 s

Being callable is a protocol, not a kind of value. When Python evaluates `obj(a, b)` it looks up `__call__` on the object's type and calls it, so any class that defines `__call__` produces instances usable exactly where a function is expected — as a `sorted` key, a `collections.defaultdict` factory, a callback. The payoff over a plain function is inspectable state: configuration and counters live as attributes you can read, reset, log or assert on in a test, instead of being hidden in a closure cell. `callable(obj)` only checks that the type supplies `__call__`; the call itself can still raise `TypeError` if the arguments do not match the signature. Use it when the object *is* one operation; if it has several behaviours, named methods say more than anonymous parentheses.

code

python · 13 lines
python
class DigestSender:
    def __init__(self):
        self.sent = 0

    def __call__(self, recipients):
        self.sent += len(recipients)
        return self.sent


send = DigestSender()
send(["[email protected]", "[email protected]"])
send(["[email protected]"])
print(send.sent, callable(send))

go deeper

for a junior

Be ready to say in one sentence that obj() runs the class's __call__ method, and to write a five-line class whose instances can be called. Knowing that callable() exists rounds the answer off.

for a middle

Explain that the lookup happens on the type, that functions and classes are themselves callable objects, and give a concrete reason to choose a callable instance over a closure — inspectable, resettable state.

for a senior

Show the judgement: __call__ is right when the object is one operation, wrong when it has several and the anonymous parentheses hide which one you meant. Mention how it reads in stack traces and in a grep.

for a principal

Own the API-design angle. Callable objects are how a codebase lets configuration and behaviour travel together, but they weaken discoverability; decide once, per library, whether policies are callables or named-method objects, and keep that consistent.

## Calling is a protocol Python has no privileged "function type" that the call syntax recognises. When the interpreter evaluates `obj(a, b)` it looks up `__call__` on `type(obj)` and invokes it as `type(obj).__call__(obj, a, b)`. Everything you already call goes through that one door: a function created by `def` or `lambda` is an object whose type provides `__call__`; a bound method is another; a `functools.partial` is another; a built-in such as `len` is another; and even a class is callable because its metaclass defines `__call__`, which is what allocates the instance and runs `__init__`. Defining `__call__` on your own class simply enrols your instances in the same club. The builtin `callable(obj)` answers exactly this question and nothing more — it reports whether the *type* supplies `__call__`. It does not promise that a particular call will succeed: an instance whose `__call__` takes two parameters is still `callable()` when you invoke it with none, and you get the usual `TypeError` about missing arguments. `isinstance(obj, collections.abc.Callable)` performs the same structural check. ## The method itself `__call__` is an ordinary method. It takes `self` plus whatever parameter list you want — positional, keyword, defaults, `*args`, `**kwargs` — and returns whatever the call expression should evaluate to. There is no restriction on the return value: it can be `None`, a result, or another callable. Because it is a normal method, it can be documented, type-annotated, overridden in a subclass and called explicitly as `obj.__call__(...)`, although you would normally just write `obj(...)`. ```python class Retrying: def __init__(self, attempts): self.attempts = attempts self.failures = 0 def __call__(self, fn, *args): for _ in range(self.attempts): try: return fn(*args) except ValueError: self.failures += 1 raise RuntimeError("out of attempts") retry = Retrying(attempts=3) print(retry(int, "12"), retry.failures) ``` ## Why not just a function? A closure can carry state too — an inner function that reads variables from an enclosing scope keeps them alive in cells. The difference is visibility and control. A callable instance keeps its state in attributes, so you can print it, mutate it between calls, expose a `reset()`, subclass it to change one step, or assert on it directly in a test. Closure state is reachable only through `__closure__` cells, which is fine for a two-line adapter and painful for anything you need to observe. That makes callable instances the natural shape for objects that are configured once and then invoked many times: a strategy or policy object; a decorator implemented as a class, where `__init__` takes the decorator's arguments and `__call__` takes the function; a scoring or key function that needs a lookup table; a rate or backoff policy that must remember what it did last; a stub you hand to code that expects a plain function. ## Where it hurts The cost of `__call__` is that the operation loses its name. A reader who meets `sender(rows)` has to find the class to learn what happens; `sender.send(rows)` tells them at the call site. So reserve `__call__` for objects whose *entire* purpose is one operation — if a class has three interesting behaviours, none of them should own the anonymous parentheses. A second, subtler cost is discoverability in tooling: searching a codebase for `.send(` finds callers; searching for a call through a variable finds nothing. One practical note for anyone writing framework-ish code: the call is dispatched on the type, so a class that wraps or proxies another object must define `__call__` itself if it wants to be callable — forwarding attribute access alone is not enough. ## Interview shape The question is usually asked as "how do you make an object callable?" and the good answer moves quickly past the mechanism to the judgement: functions and classes are both just objects that implement one protocol, callable instances buy you inspectable state, and the price is that the operation has no name at the call site.

  • How does a decorator written as a class use `__call__`?
    `__init__` receives the decorator's own configuration, and `__call__` receives the function being decorated (or, for a decorator without arguments, `__init__` takes the function and `__call__` takes the wrapped call's arguments). The instance then stands in for the function, which is why it must implement `__call__` at all — the caller invokes it with parentheses like any other function.
  • Does `callable(obj)` returning True guarantee that `obj()` will work?
    No. `callable` only reports that the object's type provides `__call__`. The call can still fail with `TypeError` for a wrong argument count or wrong keywords, or raise anything the method body raises. It is a shape check, not a contract check.
  • When would you prefer a plain function or a closure over a callable class?
    When there is no state worth inspecting, or the behaviour is a couple of lines. A closure is shorter and cheaper to read. Reach for the class once the state has to be observed, reset, subclassed or asserted on, or once the object needs other methods alongside the call.

A vending machine is a thing, not an action, yet you interact with it by pressing one button. __call__ gives an object that single button while its coin box, stock and counters stay on the inside where you can look at them.

saying these in an interview costs you the question

  • Believes only `def` and `lambda` produce callable objects
  • Confuses `__call__` with `__init__` running at construction
  • Thinks a callable instance cannot keep state between calls
  • Reaches for a callable class where a plain function fits
  • Assumes `callable(obj)` guarantees the call will succeed

context