Can we totally replace the __call__() method with call() method in a python class

In a python class I encountered, the writer only wrote the call() method and there was no __call__() method. I believe that the actual call of the object in the program calls the __call__() method so how can we skip it ? or can we ? Please throw some light on how do we handle __init__(), __call__() and call() methods.

Python has a number of special / double underscore (“dunder”) / magic methods that you can use when building data models. You can read about the __call__() method and others in the Python docs if you’d like.

The __init__() method is one of the most common special methods used when building classes. Often times it is the first method defined in a class. It is called automatically when a class instance is created (technically by the __new__() method) and is passed all the arguments fed to the class constructor expression. It’s used to perform any required initial setup of an object. The key here is that it gets automatically called when an object is first being created.

# arg_1 & arg_2 will get passed to the __init__() method on creation
new_object = Example(arg_1, arg_2)

The __call__() method can be used to make an object “callable” and emulate the syntax of a function after an object has been created. While the __init__() method is (normally) only called once at the creation of an object, the __call__() method might be utilized numerous times during the use of an object.

class Example():
   def __call__(self, *args):
        print("Special Method Call")
>>> obj = Example()
>>> obj(1,2,3)
"Special Method Call"

There is nothing stopping you from creating a class method named call() which you could use in place of the special method (and if you really want to, you could even call the special method from it).

class Example():
    def __init__(self, *args):
        print(f"Initializing Object With Args: {args}")
    def __call__(self, *args):
        print("Special Method Call")
    def call(self, *args):
        print("Custom Class Method Call")
        self.__call__(*args)
>>> obj = Example("a",  "b",  "c")
"Initializing Object With Args: ('a', 'b', 'c')"
>>> obj(1,2,3)
"Special Method Call"
>>> obj.call(1,2,3)
"Custom Class Method Call"
"Special Method Call"

In my opinion, defining a call() class method that does the same thing or uses the special method __call__() seems rather “unpythonic”. I would probably just use the special method for this myself. That said, I’ve ran into a few modules that use custom call() class methods. Normally they are referring to a different use-case of the term “call” (like how the subprocess module has a call() method in older Python 3 versions for spawning and running system or shell commands)…but not always.

2 Likes

That makes sense. In my case, the call() method was handling most of the tasks but the __call__() method was not updated to make a call to call() method. So, how is this new call() method be called when the object is called in program ? For this new call() method to be used, it has to be called from somewhere and because it is not a dunder method, we have to manually make a call to it. So, if the __call__() method is not updated to make a call to call(), how will call() be called ? Either there is something missing in the code or I am missing a concept here, please tell me what is the case ?

If no other class method is calling the call() method it would not be called unless directly used by an initialized object like so: some_object.call(arg1, arg2, ...).
In fact, if you try using the function-like “callable” syntax on an object that does not have the __call__() method specified you will get a TypeError explaining that the object is not callable. So this would fail without the dunder method being defined in the class: some_object(arg1, arg2, ...).

It’s hard to say without seeing the code you’re inspecting, but it sounds to me like the author has made their own call() method instead of using the __call__() special method, in which case if it is being used in the code you would find it being used as [self or object].call(...).
Maybe try doing a codebase search for \s?.call\( or something and see what turns up? If that turns up nothing, is this some utility code meant for you to implement?
I would also keep in mind the context of the object and ask yourself if this functionality is important to its use. I don’t know what kind of codebase this is or if it’s maintained or not, but abandoned features do happen, maybe it’s not used at all.

1 Like

Yes, actually, the class is inherited from another class so I think the dunder call of the super class calls the call() method. In my case, the code is implementing subclassed neural network model in which case, the model class inherits from the tensorflow.keras.Model class which has the __call__() method defined which calls the call() method. Is there anything you want to add ? btw thanks for your help. Here is a screenshot of a similar implementation of a Dense layer.