Jaka jest różnica między INIT a call?

Chcę poznać różnicę między metodami __init__ i __call__.

Na przykład:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20
Author: kmario23, 2012-03-12

13 answers

Pierwszy służy do inicjalizacji nowo utworzonego obiektu i otrzymuje argumenty użyte do tego celu:

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

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

Drugi implementuje operator wywołania funkcji.

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

x = Foo()
x(1, 2, 3) # __call__
 834
Author: Cat Plus Plus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-10 14:09:25

Zdefiniowanie niestandardowej metody __call__() w Meta-klasie pozwala na wywołanie instancji klasy jako funkcji, nie zawsze modyfikując samą instancję.

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

In [2]: a = A()
init

In [3]: a()
call
 283
Author: avasal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-19 10:05:08

W Pythonie funkcje są obiektami pierwszej klasy, to znaczy: odwołania do funkcji mogą być przekazywane w wejściach do innych funkcji i / lub metod i wykonywane z ich wnętrza.

instancje klas (Aka Objects), mogą być traktowane tak, jakby były funkcjami: przekazać je innym metodom / funkcjom i wywołać je. Aby to osiągnąć, funkcja klasy __call__ musi być wyspecjalizowana.

def __call__(self, [args ...]) Przyjmuje jako wejście zmienną liczbę argumentów. Zakładając x będąc instancją klasy X, x.__call__(1, 2) jest analogiczne do wywołania x(1,2) lub samej instancji jako funkcji .

W Pythonie, {[7] } jest poprawnie zdefiniowany jako konstruktor klasy (podobnie jak __del__() jest Destruktorem klasy). Dlatego istnieje rozróżnienie między __init__() i __call__(): pierwsza buduje instancję klasy up, druga sprawia, że taka instancja może być wywołana jako funkcja bez wpływu na cykl życia samego obiektu (tzn. __call__ nie wpływ na cykl życia konstrukcji/zniszczenia) , ale może modyfikować swój stan wewnętrzny (jak pokazano poniżej).

Przykład.

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
 99
Author: Paolo Maresca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-12 12:44:51

__call__ sprawia, że instancja klasy może być wywołana. Dlaczego miałoby być wymagane?

Technicznie {[1] } jest wywoływany raz przez __new__ podczas tworzenia obiektu, dzięki czemu można go zainicjować.

Ale istnieje wiele scenariuszy, w których możesz chcieć przedefiniować swój obiekt, powiedzieć, że skończyłeś z obiektem i możesz znaleźć potrzebę nowego obiektu. Za pomocą __call__ możesz na nowo zdefiniować ten sam obiekt, tak jakby był nowy.

To tylko jeden przypadek, może być o wiele więcej.
 31
Author: Mudit Verma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-06 05:12:00
>>> 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 ... 
>>> 
 22
Author: Jobin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-09 06:26:34

__init__ będzie traktowany jako konstruktor, gdzie jako __call__ metody mogą być wywoływane z obiektami dowolną ilość razy. Obie funkcje __init__ i __call__ przyjmują argumenty domyślne.

 19
Author: Vikram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-12 08:13:24

Postaram się to wyjaśnić na przykładzie, załóżmy, że chcesz wydrukować stałą liczbę terminów z serii Fibonacciego. Pamiętaj, że pierwsze 2 terminy serii Fibonacciego to 1s. np.: 1, 1, 2, 3, 5, 8, 13....

Chcesz, aby lista zawierająca liczby Fibonacciego została zainicjowana tylko raz, a następnie powinna zostać zaktualizowana. Teraz możemy użyć funkcji __call__. Przeczytaj odpowiedź @ mudit verma. To tak, jakbyś chciał, aby obiekt mógł być wywołany jako funkcja, ale nie był ponownie inicjowany co czas na Ciebie.

Eg:

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)

Wyjście To:

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__

Jeśli zauważysz, że wyjście __init__ zostało wywołane tylko jeden raz, to wtedy klasa została utworzona po raz pierwszy, później obiekt został wywołany bez ponownej inicjalizacji.

 15
Author: Ruthvik Vaila,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-24 16:05:34

Możesz również użyć metody __call__ na rzecz implementacji dekoratorów .

Ten przykład zaczerpnięty z Python 3 wzory, przepisy i idiomy

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")

Wyjście :

Tutaj wpisz opis obrazka

 8
Author: Teoman shipahi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-05 16:26:46

Tak więc, __init__ jest wywoływane, gdy tworzysz instancję dowolnej klasy i inicjalizujesz zmienną instancji.

Przykład:

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")

I __call__ jest wywoływane, gdy wywołujesz obiekt, jak każda inna funkcja.

Przykład:

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
 7
Author: Ayemun Hossain Ashik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-24 20:21:42

__call__ pozwala zwracać dowolne wartości, podczas gdy __init__ będąc konstruktorem zwraca instancję klasy niejawnie. Jak wskazywały inne odpowiedzi, __init__ jest wywoływana tylko raz, podczas gdy możliwe jest wywołanie __call__ wiele razy, w przypadku gdy inicjowana instancja jest przypisana do zmiennej pośredniej.

>>> 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'
>>> 
 5
Author: Dmitriy Sintsov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-09 07:59:29

Krótkie i słodkie odpowiedzi są już podane powyżej. Chcę dostarczyć trochę praktycznej implementacji w porównaniu z Javą.

 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

Uwaga : scenariusz 1 i scenariusz 2 wydają się takie same pod względem wyniku wyjściowego. Jednak w scenario1 ponownie tworzymy kolejną nową instancję instance1 . In scenario2, po prostu modyfikujemy już utworzony instance1 . __call__ jest tutaj korzystne, ponieważ system nie musi tworzyć nowej instancji.

Odpowiednik w 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;
        }
    }
}
 4
Author: Uddhav Gautam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-21 19:52:06

__init__ jest specjalną metodą w klasach Pythona, jest to metoda konstruktora dla klasy. Jest wywoływany, gdy obiekt klasy jest skonstruowany lub możemy powiedzieć, że inicjuje nowy obiekt. Przykład:

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

Jeśli użyjemy funkcji (), spowoduje to błąd {[3] } ponieważ wymaga 1 argumentu a ze względu na __init__.

........

__call__ gdy zaimplementowane w klasie pomaga nam wywołać instancję klasy jako wywołanie funkcji.

Przykład:

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

Tutaj jeśli użyjemy B (), działa dobrze, ponieważ nie ma tutaj funkcji __init__.

 4
Author: bhatnaushad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-12 20:09:37

Możemy użyć metody call aby użyć innych metod klasy jako metod statycznych.

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
Author: Abhishek Jain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-05 08:33:59