Constructeurs Python et __init__

107

Pourquoi les constructeurs sont-ils en effet appelés «constructeurs»? Quel est leur objectif et en quoi sont-ils différents des méthodes d'une classe?

Aussi, peut-il y en avoir plus d'un __init__dans une classe? J'ai essayé ce qui suit, quelqu'un peut-il expliquer le résultat?

>>> class test:
    def __init__(self):
        print "init 1"
    def __init__(self):
        print "init 2"

>>> s=test()
init 2

Enfin, est __init__un surchargeur d'opérateur?

Arindam Roychowdhury
la source
41
Techniquement, __init__c'est un initialiseur . Le constructeur python est __new__. Python utilise l'initialisation automatique en deux phases - __new__retourne un objet valide mais (généralement) non peuplé (voir boolpour un contre-exemple), qui l'a ensuite __init__appelé automatiquement. Cela évite les problèmes que les langages comme C ++ ont avec des objets partiellement construits - vous n'en avez jamais en Python (bien qu'il puisse être partiellement initialisé). Vous n'aurez presque jamais besoin de remplacer les deux __new__et __init__sur une classe.
Tim Delaney
2
@TimDelaney: Je ne suis pas sûr de ce que vous entendez par des objets partiellement construits en C ++.
Sebastian Mach
11
@phresnel En C ++, le type de l'objet est la classe de base (pas la sous-classe) tandis que dans le constructeur de la classe de base. Vous ne pouvez pas appeler une méthode virtuelle dans le constructeur de classe de base et demander à la sous-classe de fournir l'implémentation. En Java, vous pouvez appeler une méthode de sous-classe dans le constructeur de classe de base, mais les variables membres de sous-classe seront automatiquement initialisées après le constructeur de classe de base (et l'appel de méthode). Dans les langages avec une initialisation en deux phases comme Python, vous pouvez appeler des méthodes dans l'initialiseur de classe de base et demander à la sous-classe de fournir (ou de remplacer) le comportement.
Tim Delaney
@TimDelaney: Ah, merci d'avoir clarifié.
Sebastian Mach
4
@TimDelaney. Je pense que votre commentaire devrait remplacer la réponse acceptée.
flamenco

Réponses:

114

Il n'y a pas de surcharge de fonctions en Python, ce qui signifie que vous ne pouvez pas avoir plusieurs fonctions avec le même nom mais des arguments différents.

Dans votre exemple de code, vous ne surchargez pas __init__(). Ce qui se passe, c'est que la deuxième définition lie le nom __init__à la nouvelle méthode, rendant la première méthode inaccessible.

Quant à votre question générale sur les constructeurs, Wikipedia est un bon point de départ. Pour les éléments spécifiques à Python, je recommande vivement la documentation Python .

NPE
la source
Cela signifie-t-il également que le fichier source est analysé (interprété?) Séquentiellement? Puis-je être sûr que la fonction que j'ai définie plus tard écrase celle définie avec le même nom précédemment? :( mon Q semble idiot .. aurait dû le savoir
0xc0de
4
@ 0xc0de: En Python, les définitions de fonction sont en fait des instructions exécutables et sont exécutées de haut en bas, donc oui.
NPE
1
@ 0xc0de Ce qui se passe réellement, c'est que le corps de la classe est exécuté dans son propre espace de noms, cet espace de noms est ensuite passé à la métaclasse (parmi lesquels le nom et les bases). Les définitions de fonction créent alors simplement une fonction avec le corps spécifié et l'affectent à son nom. Le dernier devoir __init__sera ce qui se terminera dans la classe.
skyking
64

Pourquoi les constructeurs sont-ils en effet appelés «constructeurs»?

Le constructeur (nommé __new__) crée et renvoie une nouvelle instance de la classe. La C.__new__méthode de classe est donc le constructeur de la classe C.

La C.__init__méthode d'instance est appelée sur une instance spécifique, après sa création, pour l'initialiser avant d'être renvoyée à l'appelant. Cette méthode est donc l' initialiseur pour les nouvelles instances de C.

En quoi sont-elles différentes des méthodes d'une classe?

Comme indiqué dans la documentation officielle, il __init__ est appelé après la création de l'instance . Les autres méthodes ne reçoivent pas ce traitement.

Quel est leur but?

L'objectif du constructeur C.__new__est de définir un comportement personnalisé lors de la construction d'une nouvelle Cinstance.

Le but de l'initialiseur C.__init__est de définir une initialisation personnalisée de chaque instance Caprès sa création.

Par exemple Python vous permet de faire:

class Test(object):
    pass

t = Test()

t.x = 10   # here you're building your object t
print t.x

Mais si vous voulez que chaque instance de Testait un attribut xégal à 10, vous pouvez mettre ce code à l'intérieur __init__:

class Test(object):
    def __init__(self):
        self.x = 10

t = Test()
print t.x

Chaque méthode d'instance (une méthode appelée sur une instance spécifique d'une classe) reçoit l'instance comme premier argument. Cet argument est nommé de manière conventionnelle self.

Les méthodes de classe, telles que le constructeur __new__, reçoivent à la place la classe comme premier argument.

Maintenant, si vous voulez des valeurs personnalisées pour l' xattribut, tout ce que vous avez à faire est de passer cette valeur comme argument à __init__:

class Test(object):
    def __init__(self, x):
        self.x = x

t = Test(10)
print t.x
z = Test(20)
print t.x

J'espère que cela vous aidera à dissiper certains doutes, et puisque vous avez déjà reçu de bonnes réponses aux autres questions, je m'arrêterai ici :)

Rik Poggi
la source
9

Les classes sont simplement des plans à partir desquels créer des objets. Le constructeur est un code qui est exécuté chaque fois que vous créez un objet. Pour cela, il n'est pas logique d'avoir deux constructeurs. Ce qui se passe, c'est que le second écrase le premier.

Ce que vous utilisez généralement pour créer des variables pour cet objet comme ceci:

>>> class testing:
...     def __init__(self, init_value):
...         self.some_value = init_value

Vous pouvez donc créer un objet à partir de cette classe comme ceci:

>>> testobject = testing(5)

Le testobject aura alors un objet appelé some_valuequi dans cet exemple sera 5.

>>> testobject.some_value
5

Mais vous n'avez pas besoin de définir une valeur pour chaque objet comme je l'ai fait dans mon exemple. Vous pouvez également faire comme ceci:

>>> class testing:
...     def __init__(self):
...         self.some_value = 5

alors la valeur de some_value sera 5 et vous n'avez pas à le définir lorsque vous créez l'objet.

>>> testobject = testing()
>>> testobject.some_value
5

le >>> et ... dans mon échantillon n'est pas ce que vous écrivez. C'est à quoi ça ressemblerait dans Pyshell ...

Niclas Nilsson
la source
Pas de problème, heureux que cela vous ait aidé :)
Niclas Nilsson
1

les co-constructeurs sont appelés automatiquement lorsque vous créez un nouvel objet, "construisant" ainsi l'objet. La raison pour laquelle vous pouvez avoir plus d'un init est que les noms ne sont que des références en python et que vous êtes autorisé à modifier ce à quoi chaque variable fait référence quand vous le souhaitez (d'où le typage dynamique)

def func(): #now func refers to an empty funcion
    pass
...
func=5      #now func refers to the number 5
def func():
    print "something"    #now func refers to a different function

dans la définition de votre classe, il garde juste la dernière

Ryan Haining
la source
0

Il n'y a pas de notion de surcharge de méthode en Python. Mais vous pouvez obtenir un effet similaire en spécifiant des arguments optionnels et des mots-clés

PNL
la source