¿Cuál es la diferencia entre __init__ y __call__?

Quiero saber la diferencia entre los métodos __init__ y __call__ .

Por ejemplo:

 class test: def __init__(self): self.a = 10 def __call__(self): b = 20 

El primero se utiliza para inicializar el objeto recién creado y recibe los argumentos utilizados para hacerlo:

 class Foo: def __init__(self, a, b, c): # ... x = Foo(1, 2, 3) # __init__ 

El segundo implementa función de llamada al operador.

 class Foo: def __call__(self, a, b, c): # ... x = Foo() x(1, 2, 3) # __call__ 

La definición de un método __call__() en la meta-clase permite que la instancia de la clase se llame 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 

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

Las instancias de Clases (también conocidas como Objetos), se pueden tratar como si fueran funciones: pásalas a otros métodos / funciones y llámalos. Para lograr esto, la función de clase __call__ tiene que ser especializada.

def __call__(self, [args ...]) Toma como entrada un número variable de argumentos. Suponiendo que x es una instancia de la Clase X , x.__call__(1, 2) es análogo a llamar a x(1,2) o la instancia en sí misma como una función .

En Python, __init__() se define correctamente como Constructor de clases (y __del__() es el Destructor de clases). Por lo tanto, hay una distinción neta entre __init__() y __call__() : la primera construye una instancia de Class up, la segunda hace que dicha instancia se pueda llamar como una función sin afectar el ciclo de vida del objeto en sí (es decir, __call__ no tiene impacto el ciclo de vida de la 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) >>> sx 1 >>> s(7, 8) __call__ with (7,8) >>> sx 7 

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

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

Pero hay muchos escenarios en los que quizás desee redefinir su objeto, digamos que ha terminado con su objeto y que 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.

__init__ trataría como un Constructor donde como __call__ métodos pueden llamarse con objetos cualquier número de veces. Ambas funciones __init__ y __call__ toman argumentos predeterminados.

 >>> class A: ... def __init__(self): ... print "From init ... " ... >>> a = A() From init ... >>> a() Traceback (most recent call last): File "", line 1, in  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 ... >>> 

Trataré de explicarlo con un ejemplo, supongamos que desea imprimir un número fijo de términos de la serie de fibonacci. Recuerde que los primeros 2 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 después de eso debería actualizarse. Ahora podemos usar la funcionalidad __call__ . Lee la respuesta de @mudit verma. Es como si quisieras que el objeto se pueda llamar como una función pero no se reinicialice cada vez que lo llames.

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 que la salida __init__ fue llamada solo una vez que fue cuando se __init__ la instancia de la clase por primera vez, más tarde se llamó al objeto sin reinicializar.

También puede usar el método __call__ para implementar decoradores .

Este ejemplo tomado de Python 3 Patterns, Recipes and Idioms

 class decorator_without_arguments(object): def __init__(self, f): """ If there are no decorator arguments, the function to be decorated is passed to the constructor. """ print("Inside __init__()") self.f = f def __call__(self, *args): """ The __call__ method is not called until the decorated function is called. """ print("Inside __call__()") self.f(*args) print("After self.f( * args)") @decorator_without_arguments def sayHello(a1, a2, a3, a4): print('sayHello arguments:', a1, a2, a3, a4) print("After decoration") print("Preparing to call sayHello()") sayHello("say", "hello", "argument", "list") print("After first sayHello() call") sayHello("a", "different", "set of", "arguments") print("After second sayHello() call") 

Salida :

introduzca la descripción de la imagen aquí

Podemos usar el método de llamada para usar otros métodos de clase como métodos estáticos.

 class _Callable: def __init__(self, anycallable): self.__call__ = anycallable class Model: def get_instance(conn, table_name): """ do something""" get_instance = _Callable(get_instance) provs_fac = Model.get_instance(connection, "users") 

__call__ permite devolver valores arbitrarios, mientras que __init__ ser un constructor devuelve la instancia de clase implícitamente. Como otras respuestas señalaron correctamente, __init__ se llama solo una vez, mientras que es posible llamar a __call__ varias veces, en caso de que la instancia inicializada se asigne a una variable intermedia.

 >>> class Test: ... def __init__(self): ... return 'Hello' ... >>> Test() Traceback (most recent call last): File "", line 1, in  TypeError: __init__() should return None, not 'str' >>> class Test2: ... def __call__(self): ... return 'Hello' ... >>> Test2()() 'Hello' >>> >>> Test2()() 'Hello' >>> 

Las respuestas cortas y dulces ya se han proporcionado anteriormente. Quiero proporcionar alguna implementación práctica en comparación con Java.

  class test(object): def __init__(self, a, b, c): self.a = a self.b = b self.c = c def __call__(self, a, b, c): self.a = a self.b = b self.c = c instance1 = test(1, 2, 3) print(instance1.a) #prints 1 #scenario 1 #creating new instance instance1 #instance1 = test(13, 3, 4) #print(instance1.a) #prints 13 #scenario 2 #modifying the already created instance **instance1** instance1(13,3,4) print(instance1.a)#prints 13 

Nota : el escenario 1 y el escenario 2 parecen iguales en términos de resultados de resultados. Pero en el escenario 1, nuevamente creamos otra instancia de instancia1 . En el escenario 2, simplemente modificamos la instancia ya creada1 . __call__ es beneficioso aquí ya que el sistema no necesita crear una nueva instancia.

Equivalente en Java

 public class Test { public static void main(String[] args) { Test.TestInnerClass testInnerClass = new Test(). new TestInnerClass(1, 2, 3); System.out.println(testInnerClass.a); //creating new instance **testInnerClass** testInnerClass = new Test().new TestInnerClass(13, 3, 4); System.out.println(testInnerClass.a); //modifying already created instance **testInnerClass** testInnerClass.a = 5; testInnerClass.b = 14; testInnerClass.c = 23; //in python, above three lines is done by testInnerClass(5, 14, 23). For this, we must define __call__ method } class TestInnerClass /* non-static inner class */{ private int a, b,c; TestInnerClass(int a, int b, int c) { this.a = a; this.b = b; this.c = c; } } } 

__init__ es un método especial en las clases de Python, es el método constructor de una clase. Se llama cada vez que se construye un objeto de la clase o podemos decir que inicializa un nuevo objeto. Ejemplo:

  In [4]: class A: ...: def __init__(self, a): ...: print(a) ...: ...: a = A(10) # An argument is necessary 10 

Si usamos A (), dará un error TypeError: __init__() missing 1 required positional argument: 'a' ya que requiere 1 argumento a debido a __init__ .

__call__ cuando se implementa en la Clase nos ayuda a invocar la instancia de la Clase como una llamada de función.

Ejemplo:

 In [6]: class B: ...: def __call__(self,b): ...: print(b) ...: ...: b = B() # Note we didn't pass any arguments here ...: b(20) # Argument passed when the object is called ...: 20 

Aquí si usamos B (), se ejecuta bien porque no tiene una función __init__ aquí.

El método __ init__ se ejecuta automáticamente cuando se crea un objeto. Se utiliza para inicializar variables de instancia.

 class my_class(): def __init__(self,a,b): self.a = a self.b = b print("Object was created, instance variables were initialized") obj = my_class(1,2) print(obj.a) #prints 1 print(obj.b) #prints 2 

El método __ call__ se puede usar para redefinir / reinicializar los mismos objetos. También facilita el uso de instancias / objetos de una clase como funciones al pasar argumentos a los objetos.

 class my_class(): def __init__(self, a,b): self.a=a self.b=b def __call__(self,a,b): Sum = a+b return Sum obj = my_class(1,2) # a=1, b=2 Sum = obj(4,5) # a=4, b=5 instance variables are re-initialized print(Sum) # 4 + 5= 9