Entiendo que en python los objetos definidos por el usuario se pueden llamar definiendo un __call__() en la definición de clase. Por ejemplo,
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" Estaba viendo cómo pytorch hace que el método forward() de un objeto nn.Module se llame implícitamente cuando se llama al objeto y vi alguna sintaxis que no entendí.
En la línea que supuestamente define el método __call__ la sintaxis utilizada es,
__call__ : Callable[..., Any] = _call_impl Esto parecía una combinación de una anotación (palabra clave Callable[ siguiente : ignorado por python]) y un valor de _call_impl que queremos que se llame cuando se invoque __call__ , y supongo que esto es una forma abreviada de,
def __call__(self, *args, **kwargs): return self._call_impl(*args, **kwargs)pero quería entender claramente cómo funcionaba este método de definición de funciones.
Mi pregunta es: ¿Cuándo querríamos usar tal definición de atributos invocables de una clase en lugar de la def myfunc(self, *args, **kwargs)
Las funciones son objetos normales de primera clase en python. El nombre con el que define un objeto de función, por ejemplo, con una declaración def , no es inamovible, como tampoco lo sería para un int o una list . Así como puedes hacer
a = [1, 2, 3] b = a para acceder a los elementos de a mediante el nombre b , puedes hacer lo mismo con funciones. En su primer ejemplo, podría reemplazar
def __call__(self, input1): self.my_function(input1)con el mucho más simple
__call__ = my_function Debería poner esta línea después de la definición de my_function .
Las diferencias clave entre las dos implementaciones es que def __call__(... crea una nueva función. __call__ = ... simplemente vincula el nombre __call__ al mismo objeto que my_function . La diferencia notable es que si hace __call__.__name__ , el la primera versión mostrará __call__ , mientras que la segunda mostrará my_function , ya que eso es lo que asigna una declaración def .