Complete guide to Python's __call__ method covering callable objects, function-like classes, and practical examples.
Last modified April 8, 2025
This comprehensive guide explores Python’s call method, which makes instances callable like functions. We’ll cover basic usage, stateful functions, decorators, and practical examples.
The call method enables instances to be called like functions. When defined, you can use the instance with parentheses and arguments.
Key characteristics: it makes objects behave like functions, maintains state between calls, and is essential for creating functors (function objects). The method receives the instance as self plus any call arguments.
Here’s a simple class implementing call to demonstrate the basic functionality. The instance becomes callable like a function.
basic_call.py
class Greeter: def init(self, greeting): self.greeting = greeting
def __call__(self, name):
return f"{self.greeting}, {name}!"
hello = Greeter(“Hello”) print(hello(“Alice”)) # “Hello, Alice!” print(hello(“Bob”)) # “Hello, Bob!”
This example shows how call makes instances behave like functions. The Greeter instance remembers its greeting state between calls.
The hello object can be called with parentheses and arguments, just like a regular function, but maintains its own state.
call is perfect for creating stateful function objects that remember information between calls, unlike regular functions.
counter.py
class Counter: def init(self): self.count = 0
def __call__(self):
self.count += 1
return self.count
counter = Counter() print(counter()) # 1 print(counter()) # 2 print(counter()) # 3
This Counter class maintains state between calls. Each call increments the count and returns the new value, demonstrating stateful behavior.
Unlike closure-based solutions, this approach provides a clean object-oriented way to maintain state between function calls with full class capabilities.
Class-based decorators often use call to implement the decorator logic while maintaining state between decorated function calls.
decorator.py
class Trace: def init(self, func): self.func = func self.calls = 0
def __call__(self, *args, **kwargs):
self.calls += 1
print(f"Call {self.calls} to {self.func.__name__}")
return self.func(*args, **kwargs)
@Trace def square(x): return x * x
print(square(5)) # Prints trace info and returns 25 print(square(3)) # Prints trace info and returns 9
This Trace decorator logs each call to the decorated function. The call method handles the actual function invocation.
The decorator maintains state (call count) across multiple calls to the decorated function, demonstrating a key advantage of class-based decorators.
The call method can implement memoization by caching function results to avoid repeated calculations for the same inputs.
memoize.py
class Memoize: def init(self, func): self.func = func self.cache = {}
def __call__(self, *args):
if args not in self.cache:
self.cache[args] = self.func(*args)
return self.cache[args]
@Memoize def fibonacci(n): if n in (0, 1): return n return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 55 (cached results speed up calculation)
This memoization decorator caches Fibonacci sequence results to dramatically improve performance. The cache is maintained in the instance dictionary.
Each call first checks the cache before computing, storing new results for future use. This pattern works well for expensive pure functions.
call can create flexible configuration objects that behave differently based on call arguments while maintaining configuration state.
configurator.py
class Configurator: def init(self, default_mode=“standard”): self.mode = default_mode self.settings = {}
def __call__(self, mode=None, **options):
if mode:
self.mode = mode
self.settings.update(options)
return self
def get_setting(self, key):
return self.settings.get(key, f"default_{key}")
config = Configurator() config(mode=“debug”, timeout=100, retries=3) print(config.mode) # “debug” print(config.get_setting(“timeout”)) # 100
This Configurator class provides a fluent interface for configuration. The call method updates settings and returns self for chaining.
The object maintains configuration state and can be called multiple times to adjust settings, offering a flexible alternative to configuration files.
Maintain callable semantics: Make call behave like a function
Document call signature: Clearly document expected arguments
Consider functools.wraps: For decorators, preserve function metadata
Keep state clean: Manage instance state carefully between calls
Prefer simple functions: Only use call when state is needed
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.