__call__ in Python

Python is a capable and flexible programming language that gives a run of features outlined to streamline complex tasks and improve code readability. Among these highlights are the extraordinary or "enchantment" strategies that permit designers to imitate built-in behavior or execute custom functionality. One such enchantment strategy is the __call__ method, which enables Python objects to be called functions. In this article, we'll dig into the inner workings of the __call__ method, investigate its use cases, and illustrate how it can be utilized to form cleaner, more organized code.

Section 1: Understanding the __call__ Method

In Python, everything is an object, and functions are no exemption. The __call__ method permits you to create an object callable, rather than a function. By characterizing the __call__ method inside a class, you'll make occurrences of that class that carry on like functions when called. This method is ordinarily invoked when an object is called inside the event that it was a function.

Let's have a look at the syntax for the __call__ method −

class MyClass:
   def __call__(self, *args, **kwargs):
      # Implementation of the method

Here, *args and **kwargs are used to capture any positional and keyword arguments passed to the method, respectively.

Section 2: Use Cases for the __call__ Method

  • Encapsulating Functionality  The __call__ method can be utilized to encapsulate functionality inside an object, permitting you to form an organized and valid codebase. By defining the __call__ method, you'll be able to make objects that carry on like functions while still holding the benefits of object-oriented programming, such as encapsulation and inheritance.

  • Function Factories  The __call__ method is valuable when making "function factories", where you create functions with particular behavior based on certain input parameters. By utilizing the __call__ method, you'll be able make objects that create functions with the specified behavior when called.

  • Implementing Decorators  In Python, decorators are utilized to adjust the behavior of functions or methods. The __call__ method can be utilized to execute decorators as callable objects, giving an elective to utilizing nested functions or closures.

Section 3: Examples of the __call__ Method in Action

Example 1: Basic Usage

  • Define the CallableObject class with the __call__ method that takes two arguments, x, and y, and returns their sum.

  • Create an instance of CallableObject named addition.

  • Call the addition instance with arguments 3 and 4. The __call__ method is invoked, and the result is the sum 7.


class CallableObject:
   def __call__(self, x, y):
      return x + y

addition = CallableObject()
result = addition(3, 4)  



Example 2: Function Factory

  • Select the Polynomial class's sort utilizing the __init__ method, which acknowledges a list of coefficients and stores them as attributes.

  • Create a __call__ method for the Polynomial class that calculates polynomial esteem given an input x.

  • Create a quadratic polynomial example with the coefficients [1, -2, 1].

  • Call a quadratic instance using argument number three. The __call__ approach is used, and the outcome is the polynomial's value.


class Polynomial:
   def __init__(self, coefficients):
      self.coefficients = coefficients
   def __call__(self, x):
      return sum(coefficient * x**power for power, coefficient in enumerate(self.coefficients))

quadratic = Polynomial([1, -2, 1])
result = quadratic(3) 



Example 3: Implementation of a Decorator

  • Define the TimingDecorator class with an __init__ method that takes a function and stores it as an attribute.

  • Define the __call__ method in the TimingDecorator class that measures the execution time of the stored function and prints the duration.

  • Create a function slow_function that sleeps for x seconds and returns a string.

  • Apply the TimingDecorator to slow_function using the @TimingDecorator syntax.

  • Call the decorated slow_function with argument 2. The __call__ method of TimingDecorator is invoked, which measures the execution time and prints it.


class TimingDecorator:
    def __init__(self, function):
        self.function = function

    def __call__(self, *args, **kwargs):
        import time
        start_time = time.time()
        result = self.function(*args, **kwargs)
        end_time = time.time()
        print(f"Execution time: {end_time - start_time:.4f} seconds")
        return result

def slow_function(x):
    import time
    return f"Finished sleeping for {x} seconds"

result = slow_function(2)


Execution time: 2.0021 seconds
Finished sleeping for 2 seconds

Section 4: Caveats and Best Practices

  • Maintainability and Readability  Whereas the __call__ method can offer assistance to organize your code and give capable functionality, overusing it can make your code harder to get and keep up. Guarantee that you just utilize the __call__ method wisely and only when it makes your code more clear and more elemental.

  • Method Resolution Order  Be aware of the method resolution order when using the __call__ method in conjunction with inheritance. If a subclass does not override the __call__ method, it will inherit the method from its parent class. Be cautious when designing your class hierarchy to prevent unexpected behavior.


The __call__ method is a flexible and capable magic method in Python that permits you to form callable objects that carry on like functions. By utilizing cases such as encapsulating functionality, making function factories, and executing decorators, the __call__ method can be an important tool in a Python developer's weapons store. By understanding its capabilities and employing best practices, you'll tackle the control of the __call__ method to form more organized, valid, and effective code.

Updated on: 08-May-2023


Kickstart Your Career

Get certified by completing the course

Get Started