[Python-de] super()?

Martin v. Loewis martin at v.loewis.de
Wed Sep 4 23:11:25 EDT 2002


Thomas Fanslau <tfanslau at gmx.de> writes:

> (Das folgende ist vielleicht lang, aber doch nicht unwichtig. Sollte
> ich recht haben, und Test zeigen mir, das ich nicht wirklich falsch
> liege, dann muss bei der geplanten Verwendung von super() JEDE Klasse,
> selbst wenn sie keine Basisklasse ausser 'object' hat, ein
> super()-Aufruf eingetragen werden UND jeder dieser Aufrufe muss
> zumindestens mit einem try-except geklammert werden. Oder ich lieg
> völlig daneben, was ich nie völlig ausschliesse.)

Nein, Du hast es fast richtig verstanden: Man muss in jede Klasse, die
an kooperativen Methoden teilnehmen soll, einen super-Ruf eintragen,
selbst wenn sie keine Basisklasse hat, die diese Methode auch
implementiert.

Wie Christian gezeigt hat, kann man das try-except vermeiden, indem
man eine mixin-Klasse als Basisklasse einsetzt, die die Methode leer
implementiert (und darauf achtet, dass diese Basisklasse die jeweils
letzte ist)

> Und sieh an: Ein Aufruf ergibt "r a b d". Wie kann das aber sein?

super beachtet die MRO.

> class A(object):
>       def save(self):
>           print "a",
> 
> class B(object):
>      def save(self):
>          print "b",
> 
> class D(B, A):
>      def save(self):
>          super(D, self).save()
>          print "d"
> 
> d = D()
> d.save()
> 
> Und der Aufruf ergibt (anstatt "a b d" wie ich das erwartet habe) "b d".

Wieso Du das erwartest, verstehe ich nicht: Du schreibst einen
Methodenruf hin und erwartest, dass derer zwei ausgeführt werden ?!?

> Und, tata, "a b d" OBWOHL B GAR KEINE BASISKLASSE HAT!!!!

Genau. Das liegt an der MRO.

> Will ich aber
> 
> b = B()
> b.save()
> 
> sagen, spring mir das System logischerweise an den Hals, den B hat gar
> keine Basisklasse. Hahaha...

Hat es schon - aber keine, die save implementiert.

> Inzwischen glaube ich das in Wirklichkeit folgendes passiert:

Hier liegst Du ziemlich daneben.

> Alle weiteren super()-Aufrufe ignorieren alle übergebenen Parameter
> und liefern einfach die nächste Klasse aus der Liste.

Nein. super geht ungefähr so:

def super(klasse, object):
  mro = object.__class__.__mro__
  for i in range(len(mro)):
    if mro[i] is klasse:
      break
  else:
    raise TypeError, "must be an instance or subtype of type"
  return mro[i+1]

Es wird also die nächste Klasse in Method Resolution Order
zurückgegeben. Ganz so funktioniert es nicht (super ist keine
Funktion): es super(C, o).attr sucht nämlich die nächste Klasse in
mro, die attr besitzt, und nicht unbedingt die unmittelbar nächste
Klasse.

> Ist dann zwar nett, aber nach dem ich in obigem Beispiel in 'b.save()'
> eine Exception bekomme, andererseits ohne das super() dort 'a' gar
> nicht gespeichert wird, ist da irgendwo murks drin.

Nein, Du hast es bloss nicht richtig verstanden.

Ciao,
Martin




More information about the Python-de mailing list