“__init__” vs “__call__” en la clase python

7 minutos de lectura

avatar de usuario de sam
Sam

quiero saber la diferencia entre __init__ y __call__ métodos.

Por ejemplo:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

  • Esto es funcionalmente dos preguntas en una: “¿Cuál es el __init__ método para / ¿qué hace?” y “¿Cuál es el __call__ método para / ¿qué hace?” No veo ninguna razón a priori suponer que tienen algo que ver entre sí, y de hecho no es así, por lo que no hay una forma significativa de describir una “diferencia entre” ellos.

    – Karl Knechtel

    27 de julio a las 21:43

Avatar de usuario de Cat Plus Plus
gato más más

El primero se usa para inicializar un objeto recién creado y recibe los argumentos que se usan para hacerlo:

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

x = Foo(1, 2, 3) # __init__

El segundo implementa el operador de llamada de función.

class Foo:
    def __call__(self, a, b, c):
        # ...

x = Foo()
x(1, 2, 3) # __call__

  • Entonces el __init__ El método se utiliza cuando el clase se llama para inicializar la instancia, mientras que el __call__ Se llama al método cuando el instancia se llama

    – pratikm

    15 de enero de 2015 a las 17:58


  • Eso parece correcto, aparentemente las variables de instancia se pueden modificar durante la vida de una instancia, lo que puede ser beneficioso en algunos casos.

    – Murphy

    27 de diciembre de 2017 a las 19:38

  • en eso se llama al instanciar la clase: myfoo = Foo(1,4,7.8) llamar es una plantilla para llamar a la clase ya instanciada para hacer algo, digamos class Foo:\ def __call__(self, zzz) Luego, myfoo(12) llama a la clase para hacer lo que hace esa clase.

    – usuario1270710

    31/10/2018 a las 23:38


  • ¿Cuál es el uso práctico de __call__?

    – mrgloom

    13 de noviembre de 2019 a las 12:43

  • La respuesta de Dmitriy Sintsov a continuación plantea un punto muy importante, por lo que creo que debería llamar la atención aquí: __call__ puede devolver un valor arbitrariomientras __init__ debe devolver Ninguno.

    – polvo de cantor

    30 de marzo de 2020 a las 12:34

avatar de usuario de avasal
Avasal

Definición de una costumbre __call__() El método permite llamar a la instancia de la clase como una función, no siempre modificando la instancia en sí.

In [1]: class A:
   ...:     def __init__(self):
   ...:         print "init"
   ...:         
   ...:     def __call__(self):
   ...:         print "call"
   ...:         
   ...:         

In [2]: a = A()
init

In [3]: a()
call

  • __call__ no solo permite que una instancia se use como función… sino que define el cuerpo de la función que se ejecuta cuando una instancia se usa como función.

    – Arturo

    1 de septiembre de 2019 a las 17:14

Avatar de usuario de Paolo Maresca
paolo maresca

En Python, las funciones son objetos de primera clase, esto significa que las referencias a funciones se pueden pasar en entradas a otras funciones y/o métodos, y ejecutarse desde dentro de ellas.

Instancias de Clases (también conocido como Objetos), se pueden tratar como si fueran funciones: páselos a otros métodos/funciones y llámelos. Para lograr esto, el __call__ la función de clase tiene que ser especializada.

def __call__(self, [args ...])

Toma como entrada un número variable de argumentos. Asumiendo x ser una instancia de la Clase X, x.__call__(1, 2) es análogo a llamar x(1,2) o la instancia misma como una función.

en Python, __init__() se define correctamente como constructor de clase (así como __del__() es el Destructor de clases). Por lo tanto, hay una distinción neta entre __init__() y __call__(): el primero construye una instancia de Class up, el segundo crea dicha instancia invocable como sería una función sin afectar el ciclo de vida del objeto en sí (es decir, __call__ no afecta el ciclo de vida de construcción/destrucción) pero puede modificar su estado interno (como se muestra a continuación).

Ejemplo.

class Stuff(object):

    def __init__(self, x, y, range):
        super(Stuff, self).__init__()
        self.x = x
        self.y = y
        self.range = range

    def __call__(self, x, y):
        self.x = x
        self.y = y
        print '__call__ with (%d,%d)' % (self.x, self.y)

    def __del__(self):
        del self.x
        del self.y
        del self.range

>>> s = Stuff(1, 2, 3)
>>> s.x
1
>>> s(7, 8)
__call__ with (7,8)
>>> s.x
7

  • Entiendo el concepto, pero no la característica especial de modificando su estado interno. Si en el código anterior reemplazamos def __call__ simplemente con def updatele damos a la clase un update método que hace lo mismo. Ahora también puede modificar el estado interno, si se llama a continuación como s.update(7, 8). Asi es __call__ Entonces, ¿solo azúcar sintáctica?

    – Álex Povel

    6 de abril de 2020 a las 19:16

  • Sí, bastante. Es solo un atajo para invocar un método en el objeto sin molestarse en especificarlo. Aparte de eso, es como cualquier otro método de instancia. Curiosamente, si lo decora con @classmethod, sirve tanto como un método de clase como para hacer que una instancia sea invocable. Pero dado que un método de clase no puede tomarse a sí mismo, no hay estado para pasar, y tratar de llamar a una clase como llama a un método __init__así que afortunadamente no rompe la construcción de la clase.

    – Chris Iván

    13 de agosto de 2020 a las 3:57


Avatar de usuario de Mudit Verma
Mudit Verma

__call__ hace que la instancia de una clase sea invocable. ¿Por qué sería necesario?

Técnicamente __init__ es llamado una vez por __new__ cuando se crea el objeto, para que pueda inicializarse.

Pero hay muchos escenarios en los que es posible que desee redefinir su objeto, digamos que ha terminado con su objeto y puede encontrar la necesidad de un nuevo objeto. Con __call__ puede redefinir el mismo objeto como si fuera nuevo.

Este es solo un caso, puede haber muchos más.

>>> class A:
...     def __init__(self):
...         print "From init ... "
... 
>>> a = A()
From init ... 
>>> a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: A instance has no __call__ method
>>> 
>>> class B:
...     def __init__(self):
...         print "From init ... "
...     def __call__(self):
...         print "From call ... "
... 
>>> b = B()
From init ... 
>>> b()
From call ... 
>>> 

  • Creo que esta debería ser la respuesta aceptada. Responde con precisión.

    – Prasad Raghavendra

    26 de marzo de 2020 a las 2:43

Avatar de usuario de Vikram
Vikram

__init__ sería tratado como Constructor donde como __call__ Los métodos se pueden llamar con objetos cualquier número de veces. Ambas cosas __init__ y __call__ Las funciones toman argumentos predeterminados.

  • Creo que esta debería ser la respuesta aceptada. Responde con precisión.

    – Prasad Raghavendra

    26 de marzo de 2020 a las 2:43

Intentaré explicar esto usando un ejemplo, suponga que desea imprimir un número fijo de términos de la serie de Fibonacci. Recuerda que los 2 primeros términos de la serie de Fibonacci son 1s. Ej: 1, 1, 2, 3, 5, 8, 13….

Desea que la lista que contiene los números de Fibonacci se inicialice solo una vez y luego se actualice. Ahora podemos usar el __call__ funcionalidad. Lee la respuesta de @mudit verma. Es como si quisiera que el objeto se pueda llamar como una función pero no se reinicialice cada vez que lo llame.

P.ej:

class Recorder:
    def __init__(self):
        self._weights = []
        for i in range(0, 2):
            self._weights.append(1)
        print self._weights[-1]
        print self._weights[-2]
        print "no. above is from __init__"

    def __call__(self, t):
        self._weights = [self._weights[-1], self._weights[-1] + self._weights[-2]]
        print self._weights[-1]
        print "no. above is from __call__"

weight_recorder = Recorder()
for i in range(0, 10):
    weight_recorder(i)

La salida es:

1
1
no. above is from __init__
2
no. above is from __call__
3
no. above is from __call__
5
no. above is from __call__
8
no. above is from __call__
13
no. above is from __call__
21
no. above is from __call__
34
no. above is from __call__
55
no. above is from __call__
89
no. above is from __call__
144
no. above is from __call__

Si observa la salida __init__ fue llamado solo una vez que fue cuando la clase fue instanciada por primera vez, más tarde el objeto fue llamado sin reinicializar.

¿Ha sido útil esta solución?