web-dev-qa-db-fra.com

Quelle est la difference entre __init__ et __call__?

Je veux connaître la différence entre les méthodes __init__ et __call__.

Par exemple:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20
410
sam

Le premier est utilisé pour initialiser un objet nouvellement créé et reçoit les arguments utilisés pour le faire:

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

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

Le second implémente l'opérateur d'appel de fonction.

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

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

La définition d'une méthode personnalisée __call__() dans la méta-classe permet à l'instance de la classe d'être appelée en tant que fonction, mais ne modifie pas toujours l'instance elle-même.

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

En Python, les fonctions sont des objets de première classe, ce qui signifie que les références de fonction peuvent être transmises en entrée à d'autres fonctions et/ou méthodes et exécutées de l'intérieur.

Les instances de classes (ou objets) peuvent être traitées comme si elles étaient des fonctions: transmettez-les à d'autres méthodes/fonctions et appelez-les. Pour ce faire, la fonction de classe __call__ doit être spécialisée.

def __call__(self, [args ...]) Il prend en entrée un nombre variable d'arguments. Supposer que x soit une instance de la classe X, x.__call__(1, 2) est analogue à l'appel de x(1,2) ou l'instance elle-même en tant que fonction.

En Python, __init__() est correctement défini en tant que constructeur de classe (ainsi que __del__() est le destructeur de classe). Par conséquent, il existe une distinction nette entre __init__() et __call__(): le premier construit une instance de Class up, le second rend cette instance appelable en tant que fonction n’aurait aucune incidence sur le cycle de vie de l’objet lui-même (c’est-à-dire que __call__ n’a aucune incidence sur le cycle de vie de la construction/destruction), mais elle peut modifier son état interne (comme indiqué ci-dessous).

Exemple.

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__ rend l'instance d'une classe appelable. Pourquoi serait-il nécessaire?

Techniquement, __init__ est appelé une fois par __new__ lors de la création de l'objet, afin qu'il puisse être initialisé.

Mais il existe de nombreux scénarios dans lesquels vous pourriez vouloir redéfinir votre objet, par exemple en avoir terminé avec votre objet et trouver éventuellement le besoin d’un nouvel objet. Avec __call__ vous pouvez redéfinir le même objet comme s'il était neuf.

Ce n'est qu'un cas, il peut y en avoir beaucoup d'autres.

24
Mudit Verma

__init__ serait traité comme un constructeur où les méthodes __call__ pourraient être appelées avec des objets autant de fois que nécessaire. Les deux fonctions __init__ et __call__ prennent les arguments par défaut.

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

Je vais essayer d’expliquer cela à l’aide d’un exemple. Supposons que vous vouliez imprimer un nombre fixe de termes de la série Fibonacci. Rappelez-vous que les 2 premiers termes de la série de fibonacci sont des 1. Ex: 1, 1, 2, 3, 5, 8, 13 ....

Vous souhaitez que la liste contenant les numéros de fibonacci ne soit initialisée qu'une seule fois et qu'elle soit mise à jour ensuite. Nous pouvons maintenant utiliser la fonctionnalité __call__. Lisez la réponse de @mudit verma. C'est comme si vous vouliez que l'objet soit appelable en tant que fonction mais ne soit pas réinitialisé à chaque fois que vous l'appelez.

Par exemple:

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 sortie est:

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 vous observez que la sortie __init__ n'a été appelée qu'une fois, c'est-à-dire lorsque la classe a été instanciée pour la première fois, l'objet a ensuite été appelé sans être réinitialisé.

9
Ruthvik Vaila

Vous pouvez également utiliser la méthode __call__ en faveur de la mise en œuvre de décorateurs .

Cet exemple tiré 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")

Sortie :

enter image description here

5
Teoman shipahi

__init__ est une méthode spéciale dans Python classes, c'est la méthode du constructeur pour une classe. On l'appelle à chaque fois qu'un objet de la classe est construit ou qu'on peut dire qu'il initialise un nouvel objet. Exemple:

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

Si nous utilisons A (), cela donnera une erreur TypeError: __init__() missing 1 required positional argument: 'a' car il nécessite 1 argument a à cause de __init__.

........

__call__ lorsqu'il est implémenté dans la classe nous aide à appeler l'instance de classe en tant qu'appel de fonction.

Exemple:

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

Ici, si nous utilisons B (), cela fonctionne très bien car il n’a pas de fonction __init__.

3
bhatnaushad

Nous pouvons utiliser la méthode call pour utiliser d'autres méthodes de classe en tant que méthodes statiques.

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__ permet de renvoyer des valeurs arbitraires, tandis que __init__ étant un constructeur, l'instance de la classe est renvoyée implicitement. Comme d'autres réponses l'ont bien souligné, __init__ n'est appelé qu'une seule fois, alors qu'il est possible d'appeler __call__ plusieurs fois, au cas où l'instance initialisée serait affectée à une variable intermédiaire.

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

Des réponses courtes et douces sont déjà fournies ci-dessus. Je veux fournir une implémentation pratique par rapport à 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

Note: les scénarios 1 et 2 semblent identiques en termes de résultat. Mais dans scenario1, nous créons à nouveau une autre nouvelle instance instance1. Dans le scénario2, nous modifions simplement les éléments déjà créés instance1. __call__ est utile dans la mesure où le système n'a pas besoin de créer une nouvelle instance.

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