135 votes

__Init __ () doit-il appeler le __init __ () de la classe parente?

Je suis utilisés qu'en Objective-C j'ai cette construction:

- (void)init {
    if (self = [super init]) {
        // init class
    }
    return self;
}

Devrait Python aussi appeler le parent de la classe de mise en œuvre pour l' __init__?

class NewClass(SomeOtherClass):
    def __init__(self):
        SomeOtherClass.__init__(self)
        # init class

Est-ce aussi vrai/faux pour __new__() et __del__()?

Edit: Il y a une question très semblable: l'Héritage et Primordial, __init__ en Python

149voto

Anon Points 3418

Si vous avez besoin de quelque chose de super de l' __init__ à faire en plus de ce qui est fait dans la classe actuelle de l' __init__, vous devez appeler vous-même, puisque cela ne se fera pas automatiquement. Mais si vous n'avez pas besoin de quelque chose de super de l' __init__, pas besoin de l'appeler. Exemple:

>>> class C(object):
    def __init__(self):
    	self.b = 1


>>> class D(C):
    def __init__(self):
    	super().__init__()
    	self.a = 1


>>> class E(C):
    def __init__(self):
    	self.a = 1


>>> d = D()
>>> d.a
1
>>> d.b  # This works because of the call to super's init
1
>>> e = E()
>>> e.a
1
>>> e.b  # This is going to fail since nothing in E initializes b...
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    e.b  # This is going to fail since nothing in E initializes b...
AttributeError: 'E' object has no attribute 'b'

__del__ est de la même façon, (mais méfiez-vous de s'appuyer sur __del__ pour la finalisation - envisager de le faire via l'instruction à la place).

J'utilise rarement, __new__. je fais tout l'initialisation en __init__.

113voto

eyquem Points 9942

Dans Anon réponse:
"Si vous avez besoin de quelque chose de super de l' __init__ à faire en plus de ce qui est fait dans la classe actuelle de l' __init__ , vous devez appeler vous-même, car cela ne se produira pas automatiquement"

C'est incroyable: il est libellé exactement le contraire du principe de l'héritage.

.

Ce n'est pas que "quelque chose de super de l' __init__ (...) ne se fera pas automatiquement" , c'est qu'il ALLAIT se faire automatiquement, mais il n'arrive pas parce que la classe de base' __init__ est remplacée par la définition de la dérivée-clas __init__

Alors, POURQUOI la définition d'un derived_class' __init__ , puisqu'il remplace ce qui est destiné à quand quelqu'un recours à l'héritage ??

C'est parce que l'on a besoin de définir quelque chose qui n'est PAS fait dans la classe de base' __init__ , et la seule possibilité de les obtenir est de mettre son exécution dans une dérivée de la classe' __init__ fonction.
En d'autres termes, on a besoin de quelque chose dans la classe de base' __init__ de plus à ce qui allait être fait automatiquement dans la base-classe' __init__ si ce dernier n'était pas surchargée.
PAS le contraire.

.

Ensuite, le problème, c'est que le souhaité instructions présentes dans la classe de base' __init__ ne sont plus activés au moment de l'instanciation. Afin de compenser cette inactivation, quelque chose de spécial est requis: appeler explicitement la classe de base' __init__ , afin de GARDER , DE ne PAS AJOUTER, l'initialisation réalisée par la classe de base' __init__. C'est exactement ce qui est dit dans la doc officielle:

Une méthode de remplacement dans une classe dérivée peut, en fait, veulent étendre plutôt que de simplement remplacer la classe de base de la méthode du même nom. Il existe un moyen simple pour appeler la méthode de classe de base directement: il suffit de appel BaseClassName.methodname(de soi, des arguments).
http://docs.python.org/tutorial/classes.html#inheritance

C'est toute l'histoire:

  • lorsque l'objectif est de MAINTENIR l'initialisation réalisée par la classe de base, qui est pur héritage, rien de spécial n'est nécessaire, il faut juste éviter de définir une __init__ de la fonction dans la classe dérivée

  • lorsque l'objectif est de REMPLACER l'initialisation réalisée par la classe de base, __init__ doit être défini dans la dérivée de la classe

  • lorsque l'objectif est d'AJOUTER des processus à l'initialisation réalisée par la classe de base, un dérivé de la classe' __init__ doit être défini , comprenant un appel explicite à la classe de base __init__

.

Ce que je ressens étonnant dans le poste de Anon n'est pas seulement qu'il exprime le contraire de l'héritage de la théorie, mais qu'il y a eu 5 gars en passant par upvoted sans tourner les cheveux, et en plus, il y a eu personne pour réagir en 2 ans dans un fil dont le sujet doit être lu assez souvent.

69voto

Martin v. Löwis Points 61768

En Python, l'appel de la super-classe' __init__ est facultatif. Si vous l'appelez, il est alors également en option si l'utilisation de l' super identifiant, ou si explicitement le nom de la super-classe:

object.__init__(self)

Dans le cas de l'objet, l'appel de la méthode super n'est pas strictement nécessaire, depuis la super méthode est vide. De même pour __del__.

Otoh, que, pour __new__, vous devriez en effet d'appeler la méthode super, et l'utilisation de son retour en tant que l'objet nouvellement créé - à moins que vous ne souhaitiez revenir à quelque chose de différent.

20voto

SilentGhost Points 79627

Edit : (après le changement de code)
Nous n'avons aucun moyen de vous dire si vous avez besoin ou non d'appeler le __init__ votre parent (ou toute autre fonction). L'héritage fonctionnerait évidemment sans cet appel. Tout dépend de la logique de votre code: par exemple, si tous vos __init__ sont définis dans la classe parent, vous pouvez simplement ignorer __init__ classe fille.

considérons l'exemple suivant:

 >>> class A:
    def __init__(self, val):
    	self.a = val


>>> class B(A):
    pass

>>> class C(A):
    def __init__(self, val):
    	A.__init__(self, val)
    	self.a += val


>>> A(4).a
4
>>> B(5).a
5
>>> C(6).a
12
 

4voto

u0b34a0f6ae Points 14874

OMI, vous devriez l'appeler. Si votre super-classe est object , vous ne devriez pas, mais dans d'autres cas, je pense qu'il est exceptionnel de ne pas l'appeler. Comme d'autres l'ont déjà répondu, il est très pratique si votre classe n'a même pas à remplacer __init__ elle-même, par exemple lorsqu'elle n'a pas d'état interne (supplémentaire) à initialiser.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X