Super init contre parent. initialisation

une sous-classe Python peut être initialisée avec ou sans appel à super(), comme indiqué ci-dessous

class Parent(object):
    ...

class Child(Parent):

    def __init__(self):
        super(Child, self).__init__()


class Child(Parent):

    def __init__(self):
        Parent.__init__(self)

Quelle est la différence entre ces deux cas, et il est généralement préférable à l'autre?

20
demandé sur Adam Hughes 2015-03-20 21:20:09

2 réponses

le but du super est de manipuler les diamants de l'héritage. Si la classe la structure d'héritage utilise seulement l'héritage simple, puis en utilisant super () will il en résulte les mêmes appels que les appels explicites à la classe "parent".

Considérer cet héritage en diamant:

class A(object):
    def __init__(self):
        print('Running A.__init__')
        super(A,self).__init__()

class B(A):
    def __init__(self):
        print('Running B.__init__')        
        super(B,self).__init__()

class C(A):
    def __init__(self):
        print('Running C.__init__')
        super(C,self).__init__()

class D(B,C):
    def __init__(self):
        print('Running D.__init__')
        super(D,self).__init__()

foo = D()

impression

Running D.__init__
Running B.__init__
Running C.__init__
Running A.__init__

tandis que si nous changeons BB2 et utilisez des appels explicites au parent __init__:

class B2(A):
    def __init__(self):
        print('Running B.__init__')        
        A.__init__(self) 

class D2(B2,C):
    def __init__(self):
        print('Running D.__init__')
        super(D2,self).__init__()

bar = D2()

puis la chaîne d'init appels devient

Running D.__init__
Running B.__init__
Running A.__init__

Donc, l'appel à C.__init__ est complètement ignorée.


il n'y a pas d'option privilégiée.

Si vous pouvez garantir que vous ne voulez pas en charge l'héritage multiple alors les appels parents explicites sont plus simples et plus clairs.

Si vous souhaitez soutenir l'héritage multiple, maintenant ou dans l'avenir, alors vous devez utiliser super(). Mais comprendre qu'il y a certains écueils impliqué dans l'utilisation de super, mais avec bonne utilisation ces pièges peuvent être évités.

22
répondu unutbu 2015-03-20 18:38:27

Le but principal de super(Child, self).__init__(self) is permet l'initialisation correctement exécutée dans le cas d'un héritage multiple avec des structures d'héritage diamantées. Si vous appelez explicitement les constructeurs de classe de base avec un héritage multiple, certains initialiseurs peuvent être appelés deux fois. Avec un héritage unique, il n'y a pas de différence fonctionnelle entre l'utilisation de super et l'invocation explicite de la classe de base __init__() méthode. Notez que parce que toutes les classes python nouveau style objet de la sous-classe, héritage multiple toujours implique un héritage de diamant.

super a un avantage moindre de réduire nécessite des changements si vous renommez ou changez la classe de base.

en python 3, les arguments pour super sont optionnels, donc vous pouvez simplement faire super().__init__(self). Python 2 exige toujours que vous fournissiez les arguments explicitement.

7
répondu Evan 2015-03-20 18:39:08