web-dev-qa-db-fra.com

Héritage multiple Python: sélection du super () à appeler

En Python, comment choisir la méthode du parent à appeler? Disons que je veux appeler la méthode __init__ Du parent ASDF2. On dirait que je dois spécifier ASDF1 dans le super () ..? Et si je veux appeler __init__ D'ASDF3, alors je dois spécifier ASDF2 ?!

>>> class ASDF(ASDF1, ASDF2, ASDF3):
    def __init__(self):
        super(ASDF1, self).__init__()


>>> ASDF()
ASDF2's __init__ happened
>>> class ASDF(ASDF1, ASDF2, ASDF3):
    def __init__(self):
        super(ASDF2, self).__init__()


>>> ASDF()
ASDF3's __init__ happened

Semble bonkers pour moi. Qu'est-ce que je fais mal?

42
Name McChange

Ce n'est pas à ça que sert super() . Super choisit essentiellement l'un (ou tous) de ses parents dans un ordre spécifique. Si vous souhaitez uniquement appeler la méthode d'un seul parent, procédez comme suit

class ASDF(ASDF1, ASDF2, ASDF3):
    def __init__(self):
        ASDF2.__init__(self)
59
Falmarri

super appelle la méthode suivante dans l'ordre de résolution des méthodes. Dans un arbre d'héritage linéaire, ce sera la méthode de la classe immédiatement parent.

Ici, vous avez trois parents et la prochaine méthode __init__ Du point de vue de ASDF1 Est celle de ASDF2. En général, la chose sûre à faire est de passer la première classe de la liste d'héritage à super sauf si vous savez pourquoi vous voulez faire autre chose.

Le but de tout cela est de vous éviter d'avoir à choisir explicitement les méthodes __init__ À appeler. La question ici est pourquoi vous ne voulez pas appeler toutes les méthodes de la superclasse __init__.

Il existe une littérature assez importante sur l'utilisation de super en python, et je vous recommande de google le sujet et de lire les résultats.

10
Marcin

Vous passez ASDF1 (une de vos classes parentes) comme premier argument à super (). Ne fais pas ça. Au lieu de cela, vous devez passer ASDF comme premier argument à super ().

documentation Python 2.7 pour super ()

Pour citer les documents Python 2.7, un appel de superclasse typique ressemble à ceci:

class C(B):
    def method(self, arg):
        super(C, self).method(arg)

Notez que le premier argument de super ici est C, qui est la classe actuelle. Ne passez pas B (la classe parente) à super ().

Lors de la détermination de l'ordre de résolution de méthode (MRO), la classe qui est passée en tant que premier argument est ignorée et commence à regarder les parents et les frères et sœurs de cette classe. Ainsi, lorsque vous avez passé ASDF1 comme premier argument à super (), il a ignoré ASDF1 et a commencé sa recherche avec ASDF2. C'est pourquoi __init__ D'ASDF2 a été appelé.


Dans Python 3, vous n'avez plus besoin de passer la classe actuelle.

class C(B):
    def method(self, arg):
        super().method(arg)    # This does the same thing as:
                               # super(C, self).method(arg)
                               # (Python 3 only)
3
Christian Long