web-dev-qa-db-ger.com

Was ist der Unterschied zwischen __init__ und __call__?

Ich möchte den Unterschied zwischen den Methoden __init__ und __call__ kennen.

Zum Beispiel:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20
410
sam

Das erste Objekt wird zum Initialisieren des neu erstellten Objekts verwendet und empfängt die dazu verwendeten Argumente:

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

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

Der zweite implementiert den Funktionsaufrufoperator.

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

x = Foo()
x(1, 2, 3) # __call__
581
Cat Plus Plus

Durch das Definieren einer benutzerdefinierten __call__() -Methode in der Metaklasse kann die Instanz der Klasse als Funktion aufgerufen werden, wobei die Instanz selbst nicht immer geändert wird.

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

In [2]: a = A()
init

In [3]: a()
call
213
avasal

In Python sind Funktionen erstklassige Objekte. Dies bedeutet, dass Funktionsreferenzen in Eingaben an andere Funktionen und/oder Methoden übergeben und von dort aus ausgeführt werden können.

Instanzen von Klassen (auch als Objekte bezeichnet) können wie Funktionen behandelt werden: Übergeben Sie sie an andere Methoden/Funktionen und rufen Sie sie auf. Um dies zu erreichen, muss die Klassenfunktion __call__ spezialisiert werden.

def __call__(self, [args ...]) Es wird eine variable Anzahl von Argumenten als Eingabe verwendet. Angenommen, x ist eine Instanz der Klasse X, x.__call__(1, 2) entspricht dem Aufruf von x(1,2) oder die Instanz selbst als Funktion.

In Python ist __init__() ordnungsgemäß als Klassenkonstruktor definiert (und __del__() ist der Klassendestruktor). Daher gibt es einen Nettotrenner zwischen __init__() und __call__(): Der erste baut eine Instanz von Class up auf, der zweite macht eine solche Instanz aufrufbar als eine Funktion ohne Auswirkung auf den Lebenszyklus des Objekts selbst (dh __call__ hat keine Auswirkung auf den Konstruktions-/Zerstörungslebenszyklus), kann jedoch seinen internen Zustand (wie unten gezeigt) ändern.

Beispiel.

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
63
Paolo Maresca

__call__ macht die Instanz einer Klasse aufrufbar. Warum sollte es erforderlich sein?

Technisch wird __init__ einmal von __new__ aufgerufen, wenn das Objekt erstellt wird, damit es initialisiert werden kann.

Es gibt jedoch viele Szenarien, in denen Sie Ihr Objekt möglicherweise neu definieren möchten, beispielsweise wenn Sie mit Ihrem Objekt fertig sind und möglicherweise ein neues Objekt benötigen. Mit __call__ können Sie dasselbe Objekt neu definieren, als wäre es neu.

Dies ist nur ein Fall, es kann noch viel mehr geben.

24
Mudit Verma

__init__ wird als Konstruktor behandelt, wobei als __call__ Methoden mit Objekten beliebig oft aufgerufen werden können. Beide Funktionen __init__ und __call__ akzeptieren Standardargumente.

14
Vikram
>>> 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 ... 
>>> 
13
Jobin

Ich werde versuchen, dies anhand eines Beispiels zu erklären. Angenommen, Sie möchten eine feste Anzahl von Begriffen aus der Fibonacci-Reihe drucken. Denken Sie daran, dass die ersten beiden Terme der Fibonacci-Reihe Einsen sind. ZB: 1, 1, 2, 3, 5, 8, 13 ....

Sie möchten, dass die Liste mit den Fibonacci-Zahlen nur einmal initialisiert wird und danach aktualisiert wird. Jetzt können wir die Funktion __call__ verwenden. Lesen Sie die Antwort von @mudit verma. Es ist so, als ob Sie möchten, dass das Objekt als Funktion aufrufbar ist, aber nicht jedes Mal neu initialisiert wird, wenn Sie es aufrufen.

Z.B:

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)

Die Ausgabe ist:

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__

Wenn Sie beobachten, dass die Ausgabe __init__ nur einmal aufgerufen wurde, als die Klasse zum ersten Mal instanziiert wurde, wurde das Objekt später ohne Neuinitialisierung aufgerufen.

9
Ruthvik Vaila

Sie können auch die __call__ -Methode verwenden, um Dekoratoren zu implementieren.

Dieses Beispiel stammt aus 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")

Ausgabe :

enter image description here

5
Teoman shipahi

__init__ ist eine spezielle Methode in Python Klassen, es ist die Konstruktormethode für eine Klasse. Es wird immer dann aufgerufen, wenn ein Objekt der Klasse konstruiert wird, oder wir können sagen, dass es ein neues Objekt initialisiert. Beispiel:

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

Wenn wir A () verwenden, gibt es einen Fehler TypeError: __init__() missing 1 required positional argument: 'a', da 1 Argument a wegen __init__ erforderlich ist.

........

Wenn __call__ in der Klasse implementiert ist, können wir die Klasseninstanz als Funktionsaufruf aufrufen.

Beispiel:

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

Wenn wir hier B () verwenden, läuft es einwandfrei, da es hier keine __init__ -Funktion hat.

3
bhatnaushad

Wir können call verwenden, um andere Klassenmethoden als statische Methoden zu verwenden.

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")  
2
Abhishek Jain

__call__ ermöglicht die Rückgabe beliebiger Werte, während __init__ als Konstruktor implizit die Instanz der Klasse zurückgibt. Wie in anderen Antworten richtig angegeben, wird __init__ nur einmal aufgerufen, während es möglich ist, __call__ mehrmals aufzurufen, falls die initialisierte Instanz einer Zwischenvariablen zugewiesen wird.

>>> 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'
>>> 
2
Dmitriy Sintsov

Kurze und süße Antworten sind bereits oben gegeben. Ich möchte eine praktische Implementierung im Vergleich zu Java bieten.

 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

Hinweis: Szenario 1 und Szenario 2 scheinen in Bezug auf die Ergebnisausgabe identisch zu sein. In Szenario 1 erstellen wir jedoch erneut eine neue Instanz instance1. In Szenario 2 ändern wir einfach das bereits erstellte instance1. __call__ ist hier von Vorteil, da das System keine neue Instanz erstellen muss.

Entspricht 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;
        }
    }
}
2
Uddhav Gautam