Wie funktioniert Pythons super () überhaupt?

Es gibt viele großartige Ressourcen aufsuper(), einschließlichDie großer Blog-Beitrag, der viel auftaucht, sowie viele Fragen zu Stack Overflow. Ich habe jedoch das Gefühl, dass sie alle aufhören, zu erklären, wie es im allgemeinsten Fall (mit willkürlichen Vererbungsgraphen) funktioniert und was unter der Haube vor sich geh

Betrachten Sie dieses grundlegende Beispiel für die Vererbung von Diamanten:

class A(object):
    def foo(self):
        print 'A foo'

class B(A):
    def foo(self):
        print 'B foo before'
        super(B, self).foo()
        print 'B foo after'

class C(A):
    def foo(self):
        print 'C foo before'
        super(C, self).foo()
        print 'C foo after'

class D(B, C):
    def foo(self):
        print 'D foo before'
        super(D, self).foo()
        print 'D foo after'

Wenn Sie Pythons Regeln für die Reihenfolge der Methodenauflösung aus Quellen wie @ nachlesDie oder das @ nachschlagwikipedia page Für die C3-Linearisierung sehen Sie, dass die MRO @ sein mus(D, B, C, A, object). Dies wird natürlich durch @ bestätiD.__mro__:

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)

Un

d = D()
d.foo()

prints

D foo before
B foo before
C foo before
A foo
C foo after
B foo after
D foo after

Das passt zur MRO. Beachten Sie jedoch, dass obensuper(B, self).foo() imB ruft tatsächlichC.foo, während inb = B(); b.foo() es würde einfach gleich zu @ gehA.foo. Eindeutig mitsuper(B, self).foo() ist nicht einfach eine Abkürzung fürA.foo(self) wie es manchmal gelehrt wird.

super() ist sich dann offensichtlich der vorherigen Aufrufe und der Gesamt-MRO bewusst, der die Kette zu folgen versucht. Ich sehe zwei Möglichkeiten, wie dies erreicht werden könnte. Das erste ist, etwas zu tun, wie das @ zu übergebsuper Objekt selbst alsself Argument zur nächsten Methode in der Kette, die sich wie das ursprüngliche Objekt verhält, aber auch diese Informationen enthält. Dies scheint jedoch auch eine Menge Dinge zu zerstören super(D, d) is d ist falsch) und wenn ich ein wenig experimentiere, sehe ich, dass dies nicht der Fall ist.

Die andere Option besteht darin, einen globalen Kontext zu haben, in dem die MRO und die aktuelle Position gespeichert werden. Ich stelle mir den Algorithmus für @ vsuper geht so etwas wie:

Gibt es aktuell einen Kontext, in dem wir arbeiten? Wenn nicht, erstellen Sie eine, die eine Warteschlange enthält. Rufen Sie die MRO für das Klassenargument ab und stellen Sie alle Elemente außer dem ersten in die Warteschlange.Pop das nächste Element aus der MRO-Warteschlange des aktuellen Kontexts, verwenden Sie es als aktuelle Klasse beim Erstellen dessuper instance.Wenn auf eine Methode über das @ zugegriffen wisuper Instanz, suchen Sie es in der aktuellen Klasse und rufen Sie es im selben Kontext auf.

Dies ist jedoch nicht für seltsame Dinge wie die Verwendung einer anderen Basisklasse als erstes Argument für einen Aufruf von @ verantwortlicsuper, oder sogar eine andere Methode aufrufen. Ich würde gerne den allgemeinen Algorithmus dafür kennen. Kann ich diesen Kontext auch einsehen, wenn er irgendwo vorhanden ist? Kann ich damit rumspielen? Eine schreckliche Idee, aber Python erwartet normalerweise, dass Sie ein reifer Erwachsener sind, auch wenn Sie es nicht sind.

Dies führt auch viele Designüberlegungen ein. Wenn ich @ schriB Denken Sie nur an seine Beziehung zuA, dann schreibt später jemand anderesC und eine dritte Person schreibtD, meinB.foo() Methode muss @ aufrufsuper auf eine Weise, die mit @ kompatibel iC.foo() obwohl es zu dem Zeitpunkt, als ich es geschrieben habe, noch nicht existierte! Wenn ich möchte, dass meine Klasse leicht erweiterbar ist, muss ich das berücksichtigen, aber ich bin mir nicht sicher, ob es komplizierter ist, als einfach sicherzustellen, dass alle Versionen vonfoo haben identische Signaturen. Es ist auch die Frage, wann Code vor oder nach dem Aufruf von @ eingefügt werden solsuper, auch wenn es unter Berücksichtigung von @ keinen Unterschied macBur Basisklassen von @.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage