2009-09-06 4 views
96

Je suis habitué que Objective-C J'ai cette construction:__init __() doit-il appeler __init __() de la classe parente?

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

Python appellent aussi doit-mise en œuvre de la classe parente pour __init__?

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

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

Edit: Il y a une question similaire: Inheritance and Overriding __init__ in Python

+0

vous avez modifié votre code de manière significative. Je peux comprendre que 'object' original était une faute de frappe. Mais maintenant vous n'avez même pas le titre «super» de votre question. – SilentGhost

+0

Je pensais juste que super est utilisé comme nom pour la classe parent. Je ne pensais pas que quelqu'un penserait à la fonction. Je suis désolé pour tout malentendu. –

+0

Une question pourquoi pas automatique super appel: http://stackoverflow.com/questions/3782827/why-arent-pythons-superclass-init-methods-automatically-invoked –

Répondre

48

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

object.__init__(self) 

En cas d'objet, appelant la méthode super est pas strictement nécessaire, puisque le super la méthode est vide. Idem pour __del__.

OTOH, pour __new__, vous devriez en effet appeler la super méthode, et utiliser son retour comme l'objet nouvellement créé - sauf si vous voulez explicitement retourner quelque chose de différent.

+0

Donc, il n'y a pas de convention pour appeler simplement la mise en œuvre de super? –

+4

Dans les classes de style ancien, vous ne pouviez appeler le super __init__ que si la super-classe avait effectivement un __init__ défini (ce qui n'est souvent pas le cas). Par conséquent, les gens pensent généralement à appeler super méthode, plutôt que de le faire par principe. –

+1

Si la syntaxe dans python était aussi simple que '[super init]', elle serait plus courante. Juste une pensée spéculative; la super construction dans Python 2.x est un peu gênant pour moi. – u0b34a0f6ae

17

Modifier: (après le changement de code)
Il n'y a aucun moyen pour nous de vous dire si vous avez besoin ou non d'appeler vos parents __init__ (ou toute autre fonction). L'héritage fonctionnerait évidemment sans un tel appel. Tout dépend de la logique de votre code: par exemple, si tout votre __init__ est fait dans la classe parent, vous pouvez simplement ignorer la classe __init__.

Prenons 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 
+0

J'ai retiré le super appel de mon exemple, est-ce que je voulais savoir si on devrait appeler la mise en œuvre de la classe parente de __init__ ou non. –

+0

vous pourriez vouloir éditer le titre alors. mais ma réponse est toujours là. – SilentGhost

4

Il n'y a pas de règle stricte. La documentation d'une classe doit indiquer si les sous-classes doivent appeler la méthode de superclasse. Parfois, vous voulez remplacer complètement le comportement de la superclasse et, à d'autres moments, l'augmenter, c'est-à-dire appeler votre propre code avant et/ou après un appel de superclasse.

Mise à jour: La même logique de base s'applique à tout appel de méthode. Les constructeurs ont parfois besoin d'une considération spéciale (car ils établissent souvent l'état qui détermine le comportement) et de destructeurs car ils sont parallèles aux constructeurs (par exemple dans l'allocation de ressources, par exemple les connexions à la base de données). Mais la même chose pourrait s'appliquer, disons, à la méthode render() d'un widget.

Mise à jour supplémentaire: Qu'est-ce que l'OPP? Voulez-vous dire OOP? Non - une sous-classe a souvent besoin de savoir quelque chose sur la conception de la superclasse. Pas les détails de mise en œuvre internes - mais le contrat de base que la superclasse a avec ses clients (en utilisant des classes). Cela ne viole aucunement les principes de la POO. C'est pourquoi protected est un concept valide dans OOP en général (mais pas, bien sûr, en Python).

+0

Qu'en est-il de nouveau et del? –

+0

Vous avez dit que parfois on voudrait appeler son propre code avant l'appel de la superclasse. Pour ce faire, il faut connaître la mise en œuvre de la classe parente, ce qui violerait la PPO. –

3

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

107

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

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


>>> class D(C): 
    def __init__(self): 
     super().__init__() # in Python 2 use super(D, self).__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 manière, (mais méfiez-vous de compter sur __del__ pour la finalisation - envisager de le faire via le lieu avec la déclaration).

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

+2

La définition de la classe D (C) doit être corrigée comme celle de '' super (D, self) .__ init __() '' – eyquem

+9

super() .__ init __() fonctionne uniquement en Python 3. En Python 2 vous avez besoin de super (D , self) .__ init __() – Jacinda

62

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

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


Ce n'est pas « quelque chose de super __init__ de (...) ne se produira pas automatiquement », il est qu'il se passerait-il automatiquement, mais il ne se produit pas parce que la classe de base « __init__ est outrepassée par la définition des dérivés de clas __init__

alors, pourquoi la définition d'une Derived_Class » __init__, puisqu'il l'emporte sur ce qui est visé quand quelqu'un recourt à l'héritage ?? C'est parce qu'on a besoin de définir quelque chose qui n'est PAS fait dans la classe de base '__init__, et la seule possibilité d'obtenir cela est de mettre son exécution dans une fonction' __init__ de la classe dérivée.
En d'autres termes, il faut quelque chose dans la classe de base '__init__ en plus à ce qui serait fait automatiquement dans la base-classe' si ce dernier n'était pas redéfini.
PAS le contraire.


Ensuite, le problème est que les instructions présentes dans la classe de base __init__ ne sont pas souhaités 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 KEEP, NOT TO ADD, l'initialisation effectuée par la classe de base' __init__. Ce est exactement ce qui est dit dans le document officiel:

Une méthode redéfinie dans une classe dérivée peut en effet vouloir étendre plutôt que de simplement remplacer la méthode de classe de base du même nom. Il existe un moyen simple d'appeler la méthode de la classe de base directement: juste appel BaseClassName.methodname (self, arguments).
http://docs.python.org/tutorial/classes.html#inheritance

Voilà toute l'histoire:

  • lorsque l'objectif est de maintenir l'initialisation effectuée par la classe de base, qui est l'héritage pur, rien est nécessaire de procéder, il faut juste éviter à définir une fonction __init__ dans la classe dérivée

  • lorsque le but est de remplacer l'initialisation effectuée par la base de classe, __init__ doit être défini en e e dérivée de la classe

  • lorsque le but est d'ajouter des processus à l'initialisation effectuée par la base de classe, il faut définir une classe dérivée __init__, comprenant un appel explicite à la classe de base __init__


ce que je ressens étonnante dans le poste de Anon est non seulement qu'il exprime au contraire de la théorie de l'héritage, mais il y a eu 5 gars qui passent par cette upvoted sans broncher, et d'ailleurs il y a eu été personne pour réagir en 2 ans dans un fil dont le sujet intéressant doit être lu relativement souvent.

+1

J'étais persuadé que ce post allait être upvoted. J'ai peur de ne pas avoir beaucoup d'explications sur les raisons pour lesquelles. Il est plus facile de rétrograder que d'analyser un texte qui semble incompréhensible. J'ai longtemps essayé de comprendre le message de l'Anon avant de me rendre compte que c'était écrit de manière spécieuse et qu'il ne faisait pas beaucoup autorité.Peut-être que cela peut être interprété comme étant à peu près juste pour quelqu'un qui connaît l'héritage; mais je trouve cela confus lorsqu'il est lu par quelqu'un qui a des notions instables sur l'héritage, un sujet pas aussi clair que l'eau de roche en général – eyquem

+1

"J'étais sûr que cet article allait être mis à jour ..." Le problème principal est que vous êtes un peu en retard à la fête, et la plupart des gens peuvent ne pas lire au-delà des premières réponses. Grande explication par le chemin +1 – Gerrat

+0

Grande réponse c'est. – Trilarion

Questions connexes