I understand that in python user-defined objects can be made callable by defining a __call__()
method in the class definition. For example,
class MyClass:
def __init__(self):
pass
def __call__(self, input1):
self.my_function(input1)
def my_function(self, input1):
print(f"MyClass - print {input1}")
my_obj = MyClass()
# same as calling my_obj.my_function("haha")
my_obj("haha") # prints "MyClass - print haha"
I was looking at how pytorch
makes the forward()
method of a nn.Module
object be called implicitly when the object is called and saw some syntax I didn't understand.
In the line that supposedly defines the __call__
method the syntax used is,
__call__ : Callable[..., Any] = _call_impl
This seemed like a combination of an annotation (keyword Callable[
following :
ignored by python) and a value of _call_impl
which we want to be called when __call__
is invoked, and my guess is that this is a shorthand for,
def __call__(self, *args, **kwargs):
return self._call_impl(*args, **kwargs)
but wanted to understand clearly how this method of defining functions worked.
My question is: When would we want to use such a definition of callable attributes of a class instead of the usual def myfunc(self, *args, **kwargs)
CodePudding user response:
Functions are normal first-class objects in python. The name to with which you define a function object, e.g. with a def
statement, is not set in stone, any more than it would be for an int
or list
. Just as you can do
a = [1, 2, 3]
b = a
to access the elements of a
through the name b
, you can do the same with functions. In your first example, you could replace
def __call__(self, input1):
self.my_function(input1)
with the much simpler
__call__ = my_function
You would need to put this line after the definition of my_function
.
The key differences between the two implementations is that def __call__(...
creates a new function. __call__ = ...
simply binds the name __call__
to the same object as my_function
. The noticeable difference is that if you do __call__.__name__
, the first version will show __call__
, while the second will show my_function
, since that's what gets assigned by a def
statement.