Back to Blog
Python

Python Callable Objects: How to Make Instances Callable

python callable objects: Learn how Python callable objects work, implement __call__, and use callable instances for stateful callbacks and decorators.

callable__call__object-orientedfunctionsdecoratorspython
Illustration of a Python object with a call button, representing callable objects and the __call__ method.

What Makes an Object Callable?

Python callable objects are instances that implement the __call__ method, allowing them to be invoked like functions. The language checks for the presence of __call__ on the object's class. If it exists, the object is callable. You can verify this with the built-in callable() function:

class Greeter: def __call__(self, name): print(f"Hello, {name}") g = Greeter() print(callable(g)) # True g("Alice") # Hello, Alice

The __call__ method is what turns a regular instance into something that behaves like a function. This is part of Python's data model and is used throughout the standard library and third-party libraries.

Implementing call

To make a custom object callable, define a __call__ method on its class. The method can accept any arguments, just like a regular function, and can return a value. Here is a simple counter that increments each time it is called:

class Counter: def __init__(self, start=0): self.count = start def __call__(self): self.count += 1 return self.count counter = Counter(10) print(counter()) # 11 print(counter()) # 12

The instance retains state between calls, which is the key difference from a plain function. The __call__ method can also accept positional and keyword arguments, and you can combine it with other methods on the class.

Callable Objects vs Functions

A plain function is the simplest callable, but a callable object can carry state and additional methods. Use a callable object when you need to keep configuration or state across calls, or when you want to bundle related behavior with data. For example, a function that needs to remember its previous calls is easier to implement as a class with __call__ than with a global variable or a closure.

class ExponentialAverage: def __init__(self, alpha): self.alpha = alpha self.avg = None def __call__(self, value): if self.avg is None: self.avg = value else: self.avg = self.alpha * value + (1 - self.alpha) * self.avg return self.avg

Here the state is stored in the instance, making the object reusable and testable. A closure could achieve the same, but a callable object is often clearer when the logic becomes complex or when you need to expose additional methods.

Practical Use Cases

Callable objects appear in several common Python patterns:

  • Decorators: A class-based decorator can implement __call__ to wrap functions while preserving state.
  • Factories: A callable factory can be configured with parameters and then invoked to create new objects.
  • Callbacks: GUI or event-driven code often uses callable objects as callbacks that carry context.
  • Partial application: You can create a callable object that stores some arguments and applies them later.

For instance, a simple decorator that logs function calls:

class LoggingDecorator: def __init__(self, func): self.func = func self.calls = 0 def __call__(self, *args, **kwargs): self.calls += 1 print(f"Call {self.calls} of {self.func.__name__}") return self.func(*args, **kwargs) @LoggingDecorator def add(a, b): return a + b print(add(2, 3)) # logs and returns 5

The decorator instance holds the original function and a call counter. This pattern is more explicit than a closure when the decorator needs to expose attributes or methods.

Common Mistakes and Pitfalls

One common mistake is forgetting to define __call__ and then trying to call an instance. This raises a TypeError: 'MyClass' object is not callable. Always verify with callable() if you are unsure.

Another pitfall is relying on mutable state without understanding the lifecycle. A callable object that is shared across threads can cause race conditions. If you need thread safety, add appropriate locks or use thread-local state.

Also, be careful when using callable objects as default arguments in functions. The object is created once at definition time, so any state it carries persists across calls. This can lead to surprising behavior if you intended a fresh state each time.

Performance and Memory Considerations

Callable objects have a small overhead compared to plain functions because calling an instance involves an attribute lookup for __call__ and then the method call. In most applications this is negligible, but in tight loops or high-frequency callbacks, the difference can matter. If you are writing performance-critical code, measure with timeit before optimizing.

Memory usage is also slightly higher because an instance carries its own attribute dictionary. For a large number of callable objects, this can add up. If you only need a simple function with no state, a plain function or a lambda is more memory-efficient.

Advanced: Callable Objects with Parameters

You can combine __call__ with __init__ to create configurable callables. For example, a multiplier that is configured with a factor:

class Multiplier: def __init__(self, factor): self.factor = factor def __call__(self, value): return value * self.factor double = Multiplier(2) print(double(5)) # 10

This is similar to using functools.partial but gives you a full class. You can also implement __repr__ to make the object easier to debug. The flexibility of a callable object makes it a powerful tool for building clean, stateful abstractions.

python callable objects: Practical Usage and Code Examples | RYUSLOG DEV