Respostas:
O primeiro é usado para inicializar o objeto recém-criado e recebe argumentos usados para fazer isso:
class Foo:
def __init__(self, a, b, c):
# ...
x = Foo(1, 2, 3) # __init__
O segundo implementa o operador de chamada de função.
class Foo:
def __call__(self, a, b, c):
# ...
x = Foo()
x(1, 2, 3) # __call__
__call__
?
Definir um __call__()
método personalizado na meta-classe permite que a instância da classe seja chamada como uma função, nem sempre modificando a própria instância.
In [1]: class A:
...: def __init__(self):
...: print "init"
...:
...: def __call__(self):
...: print "call"
...:
...:
In [2]: a = A()
init
In [3]: a()
call
__call__
não apenas permite que uma instância seja usada como uma função ... ela define o corpo da função que é executada quando uma instância é usada como uma função.
No Python, funções são objetos de primeira classe, isto significa: referências de funções podem ser passadas em entradas para outras funções e / ou métodos, e executadas a partir delas.
Instâncias de classes (também conhecidas como Objetos), podem ser tratadas como se fossem funções: passe-as para outros métodos / funções e as chame. Para conseguir isso, o__call__
função de classe precisa ser especializada.
def __call__(self, [args ...])
Toma como entrada um número variável de argumentos. Supondo que x
seja uma instância da Classe X
, x.__call__(1, 2)
é análogo a chamada x(1,2)
ou a própria instância como uma função .
No Python, __init__()
é definido corretamente como Construtor de Classes (assim como __del__()
o Destruidor de Classes). Portanto, existe uma distinção nítida entre __init__()
e __call__()
: o primeiro cria uma instância de Class up, o segundo torna essa instância exigível como uma função sem afetar o ciclo de vida do próprio objeto (por exemplo,__call__
é, não construção / destruição), mas ele pode modificar seu estado interno (como mostrado abaixo).
Exemplo.
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
def __call__
simplesmente por def update
, damos à classe um update
método que faz a mesma coisa. Agora também pode modificar o estado interno, se chamado abaixo como s.update(7, 8)
. Então, é __call__
apenas o açúcar syntactix?
__call__
torna instável a instância de uma classe. Por que isso seria necessário?
Tecnicamente, __init__
é chamado uma vez __new__
quando o objeto é criado, para que possa ser inicializado.
Mas há muitos cenários em que você pode redefinir seu objeto, dizer que terminou com ele e pode encontrar a necessidade de um novo objeto. Com__call__
você pode redefinir o mesmo objeto como se fosse novo.
Este é apenas um caso, pode haver muito mais.
>>> 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 ...
>>>
__init__
seria tratado como Construtor, onde __call__
métodos podem ser chamados com objetos inúmeras vezes. Ambas as funções __init__
e __call__
recebem argumentos padrão.
__init__
não é uma função construtora, mas __new__
é. __init__
é chamado logo após__new__
__new__
cria a instância da classe e recebe uma classe como argumento, enquanto que __init__
é o construtor da instância e é por isso que ele recebe self
. Uma maneira fácil de ver isso é na chamada a = Foo(1,2,3)
a função que receberá os argumentos do construtor __init__
.
Vou tentar explicar isso usando um exemplo, suponha que você queira imprimir um número fixo de termos da série fibonacci. Lembre-se de que os 2 primeiros termos da série fibonacci são 1s. Por exemplo: 1, 1, 2, 3, 5, 8, 13 ....
Você deseja que a lista que contém os números de fibonacci seja inicializada apenas uma vez e depois seja atualizada. Agora podemos usar a __call__
funcionalidade. Leia a resposta de @mudit verma. É como se você desejasse que o objeto pudesse ser chamado como uma função, mas não reinicializado toda vez que você o chama.
Por exemplo:
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)
A saída é:
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__
Se você observar que a saída __init__
foi chamada apenas uma vez, foi quando a classe foi instanciada pela primeira vez, mais tarde, o objeto foi chamado sem ser reinicializado.
Você também pode usar o __call__
método em favor da implementação de decoradores .
Este exemplo, retirado de Python 3 Patterns, Recipes e 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")
Saída :
Então, __init__
é chamado quando você está criando uma instância de qualquer classe e inicializando a variável de instância também.
Exemplo:
class User:
def __init__(self,first_n,last_n,age):
self.first_n = first_n
self.last_n = last_n
self.age = age
user1 = User("Jhone","Wrick","40")
E __call__
é chamado quando você chama o objeto como qualquer outra função.
Exemplo:
class USER:
def __call__(self,arg):
"todo here"
print(f"I am in __call__ with arg : {arg} ")
user1=USER()
user1("One") #calling the object user1 and that's gonna call __call__ dunder functions
__init__
é um método especial nas classes Python, é o método construtor de uma classe. É chamado sempre que um objeto da classe é construído ou podemos dizer que inicializa um novo objeto. Exemplo:
In [4]: class A:
...: def __init__(self, a):
...: print(a)
...:
...: a = A(10) # An argument is necessary
10
Se usarmos A (), ocorrerá um erro
TypeError: __init__() missing 1 required positional argument: 'a'
, pois requer 1 argumento a
por causa de __init__
.
........
__call__
quando implementado na classe nos ajuda a chamar a instância de classe como uma chamada de função.
Exemplo:
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
Aqui, se usarmos B (), ele funciona muito bem porque não tem uma __init__
função aqui.
__call__
permite retornar valores arbitrários, enquanto __init__
ser construtor retorna a instância da classe implicitamente. Como outras respostas apontaram corretamente, __init__
é chamado apenas uma vez, enquanto é possível chamar __call__
várias vezes, caso a instância inicializada seja atribuída à variável intermediária.
>>> class Test:
... def __init__(self):
... return 'Hello'
...
>>> Test()
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __init__() should return None, not 'str'
>>> class Test2:
... def __call__(self):
... return 'Hello'
...
>>> Test2()()
'Hello'
>>>
>>> Test2()()
'Hello'
>>>
Respostas curtas e doces já são fornecidas acima. Eu quero fornecer alguma implementação prática em comparação com 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 : os cenários 1 e 2 parecem iguais em termos de resultado. Mas no cenário1, criamos novamente outra nova instância1 . No cenário2, simplesmente modificamos a instância1 criada já . __call__
é benéfico aqui, pois o sistema não precisa criar uma nova instância.
Equivalente em 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;
}
}
}
Podemos usar o método de chamada para usar outros métodos de classe 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")
__init__
método é usado quando a classe é chamada para inicializar a instância, enquanto o__call__
método é chamado quando a instância é chamada