The __call__() method enables class objects to be called like functions. When the method is defined for an object, the object can be considered as a "callable object".   

Some familiar objects that have  this method defined by default includes, functions, lambda functions and classes. This is the method that actually gets invoked when you call such objects by writing their name with parenthesis.

ExampleEdit & Run
# A demo function
def demo():
    return "Hello, World!"

#Invoke the __call__ method
print(demo.__call__()) #same as func()

#A lambda function to add two numbers
add = lambda a, b: a + b

# Invoke the call method
print(add.__call__(20, 10))

copy
Output:
Hello, World! 30 [Finished in 0.010369709692895412s]

Calling the __call__() method with a class will result with a class object being instantiated. For example:

ExampleEdit & Run
class Person:
   def __init__(self, name, age):
      self.name = name
      self.age = age

p = Person.__call__("John Doe", 30) # Same as Person("John Doe", 30)

print(p.name,", ", p.age)
copy
Output:
John Doe ,  30 [Finished in 0.010035193059593439s]

Defining the __call__() method for custom objects

Class object are not callable by default, if you want them to be callable,  you must define the __call__() method for the objects.

Syntax:
def __call__(self,  [, args...]):
    #imethod body
copy

Like all other instance methods, the __call__() method must include the self parameter in its definition.  

ExampleEdit & Run
class Example:
    def __call__(self):
        return "Hello World!"

e = Example()
print(e())
copy
Output:
Hello World! [Finished in 0.009388393722474575s]

The function can also include any other necessary parameters(alongside self) that should   be given as arguments when the object is being called.

ExampleEdit & Run
class MathOperation: 
    def __init__(self, num1, num2): 
        self.num1 = num1
        self.num2 = num2
    def __call__(self, operation): 
        output_string = "{} {} {} = {}" #Define a placeholder string for ouputs

        if operation == 'add':
            return output_string.format(self.num1, "+" ,self.num2,  self.num1 + self.num2)
        elif operation == 'sub':
            return  output_string.format(self.num1, "-", self.num2, self.num1 - self.num2)
        elif operation == 'mul':
            return  output_string.format(self.num1, "x", self.num2, self.num1 * self.num2)
        elif operation == 'div': 
            return  output_string.format(self.num1, "/", self.num2,  self.num1 / self.num2)
        else:
            return 'Invalid Operation'

math_obj = MathOperation(20, 10)

#Call the object with various parameters
print(math_obj('add'))
print(math_obj('sub'))
print(math_obj('mul'))
print(math_obj('div'))
print(math_obj('exp'))
copy
Output:
20 + 10 = 30 20 - 10 = 10 20 x 10 = 200 20 / 10 = 2.0 Invalid Operation [Finished in 0.009582858998328447s]

Whenever an object contains this method, calling the builtin function, callable() with the object returns True.

ExampleEdit & Run
class Example:
    def __call__(self):
        return "Hello World!"

e = Example()
print(e())
#The callable function checks whether an object is callable or not.
print(callable(e))
copy
Output:
Hello World! True [Finished in 0.009314929135143757s]

You have now learned how you can make your custom objects callable.