781 Stimmen

Wie rufe ich die Methode einer Elternklasse von einer Kindklasse in Python auf?

Bei der Erstellung einer einfachen Objekthierarchie in Python möchte ich die Methoden der übergeordneten Klasse von einer abgeleiteten Klasse aus aufrufen können. In Perl und Java gibt es dafür ein Schlüsselwort ( super ). In Perl könnte ich dies tun:

package Foo;

sub frotz {
    return "Bamf";
}

package Bar;
@ISA = qw(Foo);

sub frotz {
   my $str = SUPER::frotz();
   return uc($str);
}

In Python scheint es, dass ich die übergeordnete Klasse explizit nach der untergeordneten benennen muss. In dem obigen Beispiel müsste ich etwas tun wie Foo::frotz() .

Dies scheint nicht richtig zu sein, da dieses Verhalten es schwierig macht, tiefe Hierarchien zu erstellen. Wenn Kinder wissen müssen, welche Klasse eine geerbte Methode definiert hat, entstehen alle Arten von Informationsschmerzen.

Ist dies eine tatsächliche Einschränkung in Python, eine Lücke in meinem Verständnis oder beides?

3 Stimmen

Ich denke, dass die Benennung der übergeordneten Klasse keine so schlechte Idee ist. Es kann hilfreich sein, wenn die Kindklasse von mehr als einer Elternklasse erbt, da Sie die Elternklasse explizit benennen.

8 Stimmen

Die Möglichkeit, eine Klasse zu benennen, ist zwar keine schlechte Idee, aber dazu gezwungen zu werden, ist es schon.

0 Stimmen

Beachten Sie die Änderungen in der Superbehandlung zwischen Python 2 und Python 3 https://www.python.org/dev/peps/pep-3135/ . Die Benennung der Klasse ist nicht mehr erforderlich (obwohl sie zumindest manchmal immer noch eine gute Idee sein kann).

992voto

Adam Rosenfield Punkte 373807

Verwenden Sie die super() Funktion:

class Foo(Bar):
    def baz(self, **kwargs):
        return super().baz(**kwargs)

Für Python < 3 müssen Sie sich ausdrücklich für die Verwendung von Klassen im neuen Stil und verwenden:

class Foo(Bar):
    def baz(self, arg):
        return super(Foo, self).baz(arg)

64 Stimmen

Kann man nicht auch "return Bar.baz(self, arg)" machen? Wenn ja, was wäre besser?

21 Stimmen

Ja, das kann man, aber der Auftraggeber wollte wissen, wie man das macht, ohne die Oberklasse an der Aufrufstelle (in diesem Fall Bar) explizit zu nennen.

12 Stimmen

Super() ist bei Mehrfachvererbung seltsam. Es ruft die "nächste" Klasse auf. Das könnte die übergeordnete Klasse sein, oder könnte eine völlig unabhängige Klasse sein, die an anderer Stelle in der Hierarchie erscheint.

164voto

Jay Punkte 40418

Python hat auch super auch:

**super**(type[, object-or-type])

Gibt ein Proxy-Objekt zurück, das Methodenaufrufe an eine Eltern- oder Geschwisterklasse des Typs delegiert. Dies ist nützlich für den Zugriff auf geerbte Methoden, die in einer Klasse überschrieben wurden. Die Suchreihenfolge ist dieselbe wie bei getattr(), mit der Ausnahme, dass der Typ selbst übersprungen wird.

Beispiel:

class A(object):     # deriving from 'object' declares A as a 'new-style-class'
    def foo(self):
        print "foo"

class B(A):
    def foo(self):
        super(B, self).foo()   # calls 'A.foo()'

myB = B()
myB.foo()

9 Stimmen

Besseres Beispiel als das von Adam, weil Sie die Verwendung einer Klasse neuen Stils mit der Objektbasisklasse demonstriert haben. Es fehlt nur der Link zu den new-style-Klassen.

0 Stimmen

Adams hat den Vorteil, dass er sowohl Python2- als auch Python3-Formen zeigt. Dieses Beispiel funktioniert zwar mit beiden Versionen, aber das "new-style class"-Geschäft und die Argumente für super() sind Artefakte von Python2 - siehe Adams Python 3-Version für ein saubereres Code-Beispiel (in Python3 sind jetzt alle Klassen New-Style-Klassen, so dass es nicht mehr nötig ist, explizit zu erben von object y super() erfordert nicht die Klasse und self Argumente, es ist nur super() ).

1 Stimmen

Gibt es einen Unterschied zwischen dem Aufruf von super().foo() und super(B, self).foo()? Beide scheinen zu funktionieren.

90voto

Alex Martelli Punkte 805329
ImmediateParentClass.frotz(self)

ist völlig in Ordnung, egal ob die unmittelbare übergeordnete Klasse, die frotz selbst oder geerbt. super ist nur für die ordnungsgemäße Unterstützung von mehrere Vererbung (und dann funktioniert es nur, wenn jede Klasse es richtig verwendet). Generell, AnyClass.whatever wird nachschlagen whatever in AnyClass Vorfahren, wenn AnyClass nicht definiert/überschreibt, und das gilt für "Child class calling parent's method" genauso wie für jedes andere Vorkommen!

1 Stimmen

Dies setzt voraus, dass die ImmediateParentClass ebenfalls im Geltungsbereich vorhanden ist, damit diese Anweisung ausgeführt werden kann. Es reicht nicht aus, wenn das Objekt aus einem Modul importiert wird.

0 Stimmen

Was ist, wenn es sich um eine Klassenmethode handelt?

0 Stimmen

@TusharVazirani wenn die übergeordnete Klasse eine unmittelbare Klasse ist parent ist es im Rahmen der gesamten Klasse, nicht wahr?

88voto

Arun Ghosh Punkte 7282

Python 3 hat eine andere und einfachere Syntax für den Aufruf der übergeordneten Methode.

Si Foo Klasse erbt von Bar , dann von Bar.__init__ kann aufgerufen werden von Foo über super().__init__() :

class Foo(Bar):

    def __init__(self, *args, **kwargs):
        # invoke Bar.__init__
        super().__init__(*args, **kwargs)

5 Stimmen

Gut zu hören, dass Python 3 eine bessere Lösung bietet. Die Frage kommt von python 2.X. Danke für den Vorschlag aber.

32voto

yesnik Punkte 3035

Hier ist ein Beispiel für die Verwendung super() :

#New-style classes inherit from object, or from another new-style class
class Dog(object):

    name = ''
    moves = []

    def __init__(self, name):
        self.name = name

    def moves_setup(self):
        self.moves.append('walk')
        self.moves.append('run')

    def get_moves(self):
        return self.moves

class Superdog(Dog):

    #Let's try to append new fly ability to our Superdog
    def moves_setup(self):
        #Set default moves by calling method of parent class
        super(Superdog, self).moves_setup()
        self.moves.append('fly')

dog = Superdog('Freddy')
print dog.name # Freddy
dog.moves_setup()
print dog.get_moves() # ['walk', 'run', 'fly']. 
#As you can see our Superdog has all moves defined in the base Dog class

0 Stimmen

Ist das nicht ein schlechtes Beispiel? Ich glaube, es ist nicht wirklich sicher, Super zu verwenden, es sei denn, Ihre gesamte Hierarchie besteht aus "New Style"-Klassen und dem korrekten Aufruf von Super().init()

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X