Difference Between init and call in Python

What is the Difference Between __init__ and __call__ in Python?

I would like to understand the difference between the __init__ and __call__ methods in Python. For example:

class Test:

    def __init__(self):
        self.a = 10

    def __call__(self): 
        b = 20

What are their roles, how are they used, and how does the Python __call__ method differ from __init__?

Understanding __init__ and __call__ with Examples In Python, __init__ is a special method used to initialize newly created objects. It sets up instance attributes based on the arguments provided when creating the object:

class Foo:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

# Creating an object initializes it with provided arguments.
x = Foo(1, 2, 3)  # Invokes __init__
print(x.a, x.b, x.c)  # Outputs: 1 2 3

On the other hand, __call__ allows an instance of a class to behave like a callable function. It executes when the instance is called directly:

class Foo:
    def __call__(self, a, b, c):
        return a + b + c

# Create an instance and call it like a function.
x = Foo()
result = x(1, 2, 3)  # Invokes __call__
print(result)  # Outputs: 6

In summary, __init__ is for initializing the object, while __call__ turns it into something you can use like a function. Both are essential in making Python classes more versatile.

__init__: Initialization Method This method is invoked when an object is created. It initializes attributes of the object:

class Test:
    def __init__(self, value):
        self.value = value

instance = Test(42)  # `__init__` is called here
print(instance.value)  # Outputs: 42

__call__: Functionality as a Callable Object This method makes an object callable, allowing it to be used as a function:

class Test:
    def __call__(self, x, y):
        return x * y

instance = Test()  # No arguments needed for creation
print(instance(5, 6))  # Outputs: 30 (via __call__)

The python __call__ method is particularly useful for designing classes where instances need to behave like flexible, reusable functions. For example, you could create a class for mathematical operations or event handling.

The __init__ method sets up the initial configuration of the object, making it ready for use, while __call__ enables dynamic reusability of that object. Together, they create powerful patterns in Python.

Here’s an example:

class Multiplier:
    def __init__(self, factor):
        self.factor = factor  # Initialize with a multiplication factor

    def __call__(self, number):
        return number * self.factor  # Multiply input by the factor
  • Using __init__: The initialization method allows us to define different multipliers:
double = Multiplier(2)
triple = Multiplier(3)
  • Using __call__: The callable method applies the configured multiplier dynamically:
print(double(10))  # Outputs: 20 (10 * 2)
print(triple(10))  # Outputs: 30 (10 * 3)

The python __call__ method shines when creating objects that need to be both configured (via __init__) and reusable as callable functions. For instance, think of creating data processors, pipelines, or even decorators with these tools.