В чем разница между __init__ и __call__?

Я хочу знать разницу между методами __init__ и __call__.

Например:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

Ответ 1

Первый используется для инициализации вновь созданного объекта и получает аргументы, используемые для этого:

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

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

Второй реализует функцию вызова оператора.

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

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

Ответ 2

Определение настраиваемого метода __call__() в метаклассе позволяет вызвать экземпляр класса как функцию, не всегда изменяя сам экземпляр.

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

In [2]: a = A()
init

In [3]: a()
call

Ответ 3

В Python функции являются объектами первого класса, это означает: ссылки на функции могут быть переданы во входные данные для других функций и/или методов и выполнены внутри них.

Экземпляры классов (иначе называемые объектами) можно рассматривать как функции: передайте их другим методам/функциям и вызовите их. Для этого __call__ класса __call__ должна быть специализированной.

def __call__(self, [args...]) Он принимает в качестве входных данных переменное число аргументов. Предполагая, что x является экземпляром класса X, x.__call__(1, 2) аналогичен вызову x(1,2) или самого экземпляра как функции.

В Python __init__() правильно определен как конструктор класса (так же как __del__() является деструктором класса). Таким образом, между __init__() и __call__() существует четкое различие: первый создает экземпляр класса up, второй делает такой экземпляр вызываемым, так как функция не влияет на жизненный цикл самого объекта (т. __call__ не влияет жизненный цикл строительства/разрушения), но он может изменить свое внутреннее состояние (как показано ниже).

Пример.

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

Ответ 4

>>> class A:
...      def __init__(self):
...          print "init"
...          
...      def __call__(self):
...          print "call"
... 
>>> 
>>> A()
init
>>> A()()
init
call

Ответ 5

__call__ делает экземпляр класса вызываемым. Зачем это нужно?

Технически __init__ вызывается один раз __new__ при создании объекта, чтобы его можно было инициализировать.

Но есть много сценариев, в которых вы, возможно, захотите переопределить свой объект, скажите, что вы сделали с вашим объектом, и можете найти необходимость в новом объекте. С помощью __call__ вы можете переопределить тот же объект, как если бы он был новым.

Это всего лишь один случай, их может быть гораздо больше.

Ответ 6

__init__ будет рассматриваться как конструктор, где методы __call__ могут быть вызваны с объектами сколько угодно раз. Обе функции __init__ и __call__ принимают аргументы по умолчанию.

Ответ 7

>>> 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 ... 
>>> 

Ответ 8

Я попытаюсь объяснить это на примере, предположим, что вы хотите напечатать фиксированное число терминов из ряда Фибоначчи. Помните, что первые 2 члена ряда Фибоначчи - 1 с. Например: 1, 1, 2, 3, 5, 8, 13....

Вы хотите, чтобы список, содержащий числа Фибоначчи, был инициализирован только один раз, и после этого он должен обновиться. Теперь мы можем использовать функциональность __call__. Прочитайте @mudit verma answer. Как будто вы хотите, чтобы объект вызывался как функция, но не переинициализировался при каждом вызове.

Например:

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)

Выход:

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__

Если вы заметили, что вывод __init__ вызывался только один раз, когда экземпляр класса создавался впервые, позже объект вызывался без повторной инициализации.

Ответ 9

Вы также можете использовать метод __call__ в пользу реализации декораторов.

Этот пример взят из 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")

Выход:

enter image description here

Ответ 10

Мы можем использовать метод call для использования других методов класса в качестве статических методов.

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

Ответ 11

__call__ позволяет возвращать произвольные значения, а __init__ будучи конструктором, неявно возвращает экземпляр класса. Как правильно указали другие ответы, __init__ вызывается только один раз, в то время как можно вызывать __call__ несколько раз, если инициализированный экземпляр назначен промежуточной переменной.

>>> 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'
>>> 

Ответ 12

Короткие и приятные ответы уже приведены выше. Я хочу предоставить некоторую практическую реализацию по сравнению с 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

Примечание: сценарий 1 и сценарий 2 выглядят одинаково с точки зрения вывода результатов. Но в сценарии 1 мы снова создаем еще один новый экземпляр instance1. В сценарии 2 мы просто модифицируем уже созданный экземпляр 1. __call__ здесь полезен, поскольку системе не нужно создавать новый экземпляр.

Эквивалент в 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;
        }
    }
}

Ответ 13

__init__ - это специальный метод в классах Python, это метод конструктора для класса. Он вызывается всякий раз, когда создается объект класса или мы можем сказать, что он инициализирует новый объект. Пример:

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

Если мы используем A(), он выдаст ошибку TypeError: __init__() missing 1 required positional argument: 'a' поскольку он требует 1 аргумент a из-за __init__.

........

__call__ при реализации в Class помогает нам вызывать экземпляр Class как вызов функции.

Пример:

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

Здесь, если мы используем B(), он работает просто отлично, потому что здесь нет функции __init__.

Ответ 14

Метод __ init__ запускается автоматически при создании объекта. Он используется для инициализации переменных экземпляра.

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

Метод __ call__ может использоваться для переопределения/повторной инициализации тех же объектов. Это также облегчает использование экземпляров/объектов класса в качестве функций путем передачи аргументов объектам.

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