Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 3135 – Neues Super

Autor:
Calvin Spealman <ironfroggy at gmail.com>, Tim Delaney <timothy.c.delaney at gmail.com>, Lie Ryan <lie.1296 at gmail.com>
Status:
Final
Typ:
Standards Track
Erstellt:
28. Apr. 2007
Python-Version:
3.0
Post-History:
28. Apr. 2007, 29. Apr. 2007, 29. Apr. 2007, 14. Mai 2007, 12. Mär. 2009

Inhaltsverzeichnis

Nummerierungs-Hinweis

Dieser PEP hatte seinen Ursprung in PEP 367. Da er nun für Python 3000 vorgesehen ist, wurde er in den 3xxx-Bereich verschoben.

Zusammenfassung

Dieser PEP schlägt eine syntaktische Vereinfachung für die Verwendung des super-Typs vor, um automatisch Instanzen des Supertyps zu erstellen, die an die Klasse, in der eine Methode definiert wurde, und an die Instanz (oder das Klassenobjekt für Klassenmethoden), auf die die Methode gerade wirkt, gebunden sind.

Die Prämisse der neuen Super-Verwendung ist wie folgt:

super().foo(1, 2)

um das alte zu ersetzen

super(Foo, self).foo(1, 2)

Begründung

Die aktuelle Verwendung von super erfordert die explizite Übergabe sowohl der Klasse als auch der Instanz, von der aus es operieren muss, was gegen die DRY (Don't Repeat Yourself)-Regel verstößt. Dies behindert jede Namensänderung der Klasse und wird von vielen als störend empfunden.

Spezifikation

Innerhalb des Spezifikationsabschnitts werden einige spezielle Begriffe verwendet, um ähnliche und eng verwandte Konzepte zu unterscheiden. „Superklasse“ bezieht sich auf die tatsächliche eingebaute Klasse namens „super“. Eine „Superinstanz“ ist einfach eine Instanz der Superklasse, die mit einer anderen Klasse und möglicherweise mit einer Instanz dieser Klasse verbunden ist.

Die neuen super-Semantiken sind nur in Python 3.0 verfügbar.

Ersetzt die alte Verwendung von super; Aufrufe der nächsten Klasse in der MRO (Method Resolution Order) können ohne explizite Übergabe des Klassenobjekts erfolgen (obwohl dies weiterhin unterstützt wird). Jede Funktion hat eine Zelle namens __class__, die das Klassenobjekt enthält, in dem die Funktion definiert ist.

Die neue Syntax

super()

ist äquivalent zu

super(__class__, <firstarg>)

wobei __class__ die Klasse ist, in der die Methode definiert wurde, und <firstarg> der erste Parameter der Methode ist (normalerweise self für Instanzmethoden und cls für Klassenmethoden). Für außerhalb eines Klassenkörpers definierte Funktionen ist __class__ nicht definiert und führt zu einem Laufzeitfehler SystemError.

Obwohl super kein reserviertes Wort ist, erkennt der Parser die Verwendung von super in einer Methodendefinition und übergibt die Zelle __class__ nur, wenn dies gefunden wird. Daher funktioniert ein globaler Alias von super ohne Argumente nicht unbedingt.

Geschlossene Probleme

Bestimmung des zu verwendenden Klassenobjekts

Das Klassenobjekt wird aus einer Zelle namens __class__ entnommen.

Sollte super tatsächlich ein Schlüsselwort werden?

Nein. Es ist nicht notwendig, dass super ein Schlüsselwort wird.

super verwendet mit \_\_call\_\_-Attributen

Es wurde erwogen, dass die Instanziierung von Superinstanzen auf klassische Weise problematisch sein könnte, da ein Aufruf die \_\_call\_\_-Attribute nachschlagen und somit versuchen würde, einen automatischen Super-Lookup zur nächsten Klasse in der MRO durchzuführen. Dies erwies sich jedoch als falsch, da ein Aufruf eines Objekts nur die \_\_call\_\_-Methode direkt auf dem Typ des Objekts nachschlägt. Das folgende Beispiel zeigt dies in Aktion.

class A(object):
    def __call__(self):
        return '__call__'
    def __getattribute__(self, attr):
        if attr == '__call__':
            return lambda: '__getattribute__'
a = A()
assert a() == '__call__'
assert a.__call__() == '__getattribute__'

In jedem Fall entfällt dieses Problem vollständig, da klassische Aufrufe von super(<class>, <instance>) weiterhin mit derselben Bedeutung unterstützt werden.

Alternative Vorschläge

Keine Änderungen

Obwohl es immer attraktiv ist, die Dinge so zu belassen, wie sie sind, haben die Leute seit einiger Zeit eine Änderung in der Verwendung von Super-Aufrufen gesucht, und das aus gutem Grund, wie zuvor erwähnt.

  • Entkopplung vom Klassennamen (der möglicherweise nicht einmal mehr an die richtige Klasse gebunden ist!)
  • Einfacher aussehende, sauberere Super-Aufrufe wären besser.

Dynamisches Attribut vom Supertyp

Der Vorschlag fügt dem Supertyp ein dynamisches Attribut-Lookup hinzu, das automatisch die richtigen Klassen- und Instanzparameter ermittelt. Jedes Super-Attribut-Lookup identifiziert diese Parameter und führt das Super-Lookup auf der Instanz durch, so wie die aktuelle Super-Implementierung dies mit der expliziten Invokation einer Superinstanz auf eine Klasse und Instanz tut.

Dieser Vorschlag stützt sich auf sys.\_getframe(), was für alles andere als eine Prototyp-Implementierung ungeeignet ist.

self.\_\_super\_\_.foo(*args)

Das \_\_super\_\_-Attribut wird in diesem PEP an mehreren Stellen erwähnt und könnte für die vollständige Lösung in Frage kommen, indem es tatsächlich explizit anstelle einer direkten Super-Verwendung genutzt wird. Doppelunterstrich-Namen sind jedoch normalerweise interne Details und es wird versucht, sie aus dem alltäglichen Code herauszuhalten.

super(self, *args) oder \_\_super__(self, *args)

Diese Lösung löst nur das Problem der Typenanzeige, behandelt keine unterschiedlich benannten Super-Methoden und ist explizit bezüglich des Instanznamens. Sie ist weniger flexibel, da sie nicht auf andere Methodennamen angewendet werden kann, wenn dies erforderlich ist. Ein Anwendungsfall, der hier fehlschlägt, ist, wo eine Basisklasse eine Factory-Klassenmethode hat und eine Unterklasse zwei Factory-Klassenmethoden hat, die beide ordnungsgemäß Super-Aufrufe an die Basisklasse machen müssen.

super.foo(self, *args)

Diese Variante eliminiert tatsächlich die Probleme bei der Lokalisierung der richtigen Instanz, und wenn eine der Alternativen ins Rampenlicht gerät, dann diese.

super(*p, **kw)

Es gab den Vorschlag, dass der direkte Aufruf von super(*p, **kw) dem Aufruf der Methode auf dem super-Objekt mit demselben Namen wie die aktuell ausgeführte Methode entsprechen würde, d. h. die folgenden beiden Methoden wären äquivalent:

def f(self, *p, **kw):
    super.f(*p, **kw)
def f(self, *p, **kw):
    super(*p, **kw)

Es gibt hierfür starke Befürworter und Gegner, aber Implementierungs- und Stilbedenken sind offensichtlich. Guido hat vorgeschlagen, dies aus diesem PEP nach dem KISS-Prinzip (Keep It Simple Stupid) auszuschließen.

Historie

29. Apr. 2007
  • Titel von „Super Als Schlüsselwort“ zu „Neues Super“ geändert.
  • Viel von der Sprache aktualisiert und einen Terminologie-Abschnitt hinzugefügt, um an verwirrenden Stellen Klarheit zu schaffen.
  • Referenzimplementierungs- und Historienabschnitte hinzugefügt.
06. Mai 2007
  • Aktualisiert von Tim Delaney, um Diskussionen auf den Python-3000- und Python-Dev-Mailinglisten widerzuspiegeln.
12. Mär. 2009
  • Aktualisiert, um den aktuellen Stand der Implementierung widerzuspiegeln.

Referenzen

[1] Fix super, irgendjemand? (https://mail.python.org/pipermail/python-3000/2007-April/006667.html)

[2] PEP 3130: Zugriff auf die aktuell definierte Modul-/Klassen-/Funktion (dies) (https://mail.python.org/pipermail/python-ideas/2007-April/000542.html)


Quelle: https://github.com/python/peps/blob/main/peps/pep-3135.rst

Zuletzt geändert: 2025-02-01 08:55:40 GMT