Die Methode einer Elternklasse aus der Kinderklasse aufrufen?

608

Wenn Sie eine einfache Objekthierarchie in Python erstellen, möchte ich Methoden der übergeordneten Klasse aus einer abgeleiteten Klasse aufrufen können. In Perl und Java gibt es ein Schlüsselwort für this ( super). In Perl könnte ich Folgendes 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 vom untergeordneten benennen muss. Im obigen Beispiel müsste ich so etwas tun 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 Informationsschmerz.

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

jjohn
quelle
3
Ich denke, die Benennung der Elternklasse ist keine so schlechte Idee. Dies kann hilfreich sein, wenn die untergeordnete Klasse von mehr als einem übergeordneten Element erbt, da Sie die übergeordnete Klasse explizit benennen.
7
Eine Option, eine Klasse zu benennen, ist zwar keine schlechte Idee, aber sicherlich dazu gezwungen zu sein.
Johndodo
Beachten Sie die Änderungen im Super-Handling zwischen Python 2 und Python 3 https://www.python.org/dev/peps/pep-3135/ . Die Benennung der Klasse ist nicht mehr erforderlich (obwohl dies zumindest manchmal immer noch eine gute Idee ist).
Jwpfox

Antworten:

736

Ja, aber nur mit neuen Klassen . Verwenden Sie die super()Funktion:

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

Verwenden Sie für Python <3:

class Foo(Bar):
    def baz(self, arg):
        return super(Foo, self).baz(arg)
Adam Rosenfield
quelle
53
Können Sie nicht auch "Bar.baz (self, arg) zurückgeben"? Wenn ja, welches wäre besser?
15
Ja, das können Sie, aber das OP hat gefragt, wie es geht, ohne die Oberklasse an der Anrufstelle explizit zu benennen (in diesem Fall Bar).
Adam Rosenfield
7
super () ist komisch mit Mehrfachvererbung. Es ruft zur "nächsten" Klasse auf. Dies kann die übergeordnete Klasse sein oder eine völlig unabhängige Klasse, die an anderer Stelle in der Hierarchie angezeigt wird.
Steve Jessop
6
Ich benutze Python 2.x und bekomme "Fehler: muss Typ sein, nicht classobj", wenn ich das mache
Chris F
28
Die Syntax super(Foo, self)ist für Python 2.x richtig? In Python 3.x ist das super()bevorzugt richtig?
Trevor Boyd Smith
144

Python hat auch super :

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

Gibt ein Proxy-Objekt zurück, das Methodenaufrufe an eine übergeordnete oder Geschwisterklasse vom Typ delegiert. Dies ist nützlich, um auf geerbte Methoden zuzugreifen, die in einer Klasse überschrieben wurden. Die Suchreihenfolge ist dieselbe wie die von getattr () verwendete, außer 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()
Jay
quelle
7
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 Klassen neuen Stils.
Samuel
83
ImmediateParentClass.frotz(self)

wird in Ordnung sein, ob die unmittelbare übergeordnete Klasse sich frotzselbst definiert oder geerbt hat. superwird nur für die ordnungsgemäße Unterstützung der Mehrfachvererbung benötigt (und funktioniert dann nur, wenn jede Klasse sie ordnungsgemäß verwendet). Im Allgemeinen AnyClass.whateverwird whateverin AnyClassden Vorfahren nachgeschlagen, wenn AnyClasses nicht definiert / überschrieben wird, und dies gilt für "untergeordnete Klasse, die die Methode der Eltern aufruft" wie für jedes andere Vorkommen!

Alex Martelli
quelle
Dies setzt voraus, dass die ImmediateParentClass auch im Umfang vorhanden ist, damit diese Anweisung ausgeführt werden kann. Nur das Objekt aus einem Modul importieren zu lassen, hilft nicht.
Tushar Vazirani
Was ist, wenn es eine Klassenmethode ist?
Shiplu Mokaddim
@TusharVazirani Wenn die übergeordnete Klasse eine unmittelbare Klasse ist parent, liegt sie im Umfang der gesamten Klasse, nicht wahr ?
Jaroslaw Nikitenko
1
@YaroslavNikitenko Ich spreche über das Importieren einer Instanz, nicht der Klasse.
Tushar Vazirani
1
@TusharVazirani jetzt verstehe ich, danke. Ich dachte darüber nach, von der Methode der aktuellen Klasse aus aufzurufen (wie vom OP angegeben).
Jaroslaw Nikitenko
75

Python 3 hat eine andere und einfachere Syntax zum Aufrufen der übergeordneten Methode.

Wenn die FooKlasse von erbt Bar, Bar.__init__kann from von Foovia aufgerufen werden super().__init__():

class Foo(Bar):

    def __init__(self, *args, **kwargs):
        # invoke Bar.__init__
        super().__init__(*args, **kwargs)
Arun Ghosh
quelle
5
Gut zu hören, dass Python 3 eine bessere Lösung hat. Die Frage kommt von Python 2.X. Vielen Dank für den Vorschlag.
John
46

In vielen Antworten wurde erklärt, wie eine Methode vom Elternteil aufgerufen wird, die im Kind überschrieben wurde.

jedoch

"Wie ruft man die Methode einer Elternklasse von der Kindklasse auf?"

könnte auch nur bedeuten:

"Wie nennt man geerbte Methoden?"

Sie können Methoden aufrufen, die von einer übergeordneten Klasse geerbt wurden, als wären sie Methoden der untergeordneten Klasse, sofern sie nicht überschrieben wurden.

zB in Python 3:

class A():
  def bar(self, string):
    print("Hi, I'm bar, inherited from A"+string)

class B(A):
  def baz(self):
    self.bar(" - called by baz in B")

B().baz() # prints out "Hi, I'm bar, inherited from A - called by baz in B"

Ja, das mag ziemlich offensichtlich sein, aber ich glaube, ohne darauf hinzuweisen, können die Leute diesen Thread mit dem Eindruck verlassen, dass man durch lächerliche Reifen springen muss, um auf geerbte Methoden in Python zuzugreifen. Zumal diese Frage bei der Suche nach "Zugriff auf die Methode einer übergeordneten Klasse in Python" einen hohen Stellenwert hat und das OP aus der Perspektive einer neuen Python-Person geschrieben wurde.

Ich fand: https://docs.python.org/3/tutorial/classes.html#inheritance hilfreich, um zu verstehen, wie Sie auf geerbte Methoden zugreifen.

Ben
quelle
@gizzmole in welcher Situation funktioniert das nicht? Ich füge gerne relevante Vorbehalte oder Warnungen hinzu, konnte aber nicht herausfinden, wie relevant der von Ihnen gepostete Link für diese Antwort war.
Ben
@ Ben Entschuldigung, ich habe deine Antwort nicht sorgfältig genug gelesen. Diese Antwort beantwortet nicht die Frage, wie Funktionen überladen werden sollen, sondern eine andere Frage. Ich habe meinen ersten Kommentar gelöscht.
Gizzmole
@gizzmole ah, keine Sorge. Mir ist klar, dass diese Antwort nicht für Überladungsfunktionen gilt, die Frage erwähnt jedoch nicht explizit Überladung (obwohl das angegebene Perl-Beispiel einen Fall von Überladung zeigt). Die überwiegende Mehrheit der anderen Antworten bezieht sich auf Überlastung - diese ist für diejenigen gedacht, die sie nicht benötigen.
Ben
@ Ben was ist, wenn ich B (). Baz () aus einer anderen Klasse namens 'C' mit in C definierten Variablen aufrufen möchte?. Ich habe versucht, B (). Baz () in Klasse C zu machen, wobei self.string ein weiterer Wert ist. Es gab mir keine, als ich hingerichtet habe
Joey
@joey Ich bin mir nicht sicher, was Sie versuchen oder ob es im Rahmen dieser Frage liegt. String ist eine lokale Variable - die Einstellung self.stringbewirkt nichts. In der Klasse C konnte man jedoch noch anrufenB().bar(string)
Ben
27

Hier ist ein Beispiel für die Verwendung von 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
yesnik
quelle
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 ruft Super () richtig auf. Init ()
Jaykul
14

Es gibt auch ein super () in Python. Es ist ein bisschen wackelig, wegen Pythons Klassen im alten und neuen Stil, wird aber ziemlich häufig verwendet, z. B. in Konstruktoren:

class Foo(Bar):
    def __init__(self):
        super(Foo, self).__init__()
        self.baz = 5
Lawrence
quelle
10

Ich würde empfehlen, so CLASS.__bases__ etwas zu verwenden

class A:
   def __init__(self):
        print "I am Class %s"%self.__class__.__name__
        for parentClass in self.__class__.__bases__:
              print "   I am inherited from:",parentClass.__name__
              #parentClass.foo(self) <- call parents function with self as first param
class B(A):pass
class C(B):pass
a,b,c = A(),B(),C()
Joran Beasley
quelle
1
Denken Sie daran , dass die Leute , wie Sie dem Umfang der Verweise auf Super hier entnehmen können, es wirklich ablehnen, Basen zu verwenden , es sei denn, Sie tun etwas wirklich Tiefes. Wenn du Super nicht magst , schau dir mro an . Der erste Eintrag in mro ist sicherer als zu verfolgen, welcher Eintrag in Basen verwendet werden soll. Die Mehrfachvererbung in Python scannt bestimmte Dinge rückwärts und andere vorwärts, sodass es am sichersten ist, wenn die Sprache den Prozess abwickelt.
Jon Jay Obermark
5

Es gibt auch ein super () in Python.

Beispiel dafür, wie eine Superklassenmethode von einer Unterklassenmethode aufgerufen wird

class Dog(object):
    name = ''
    moves = []

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

    def moves_setup(self,x):
        self.moves.append('walk')
        self.moves.append('run')
        self.moves.append(x)
    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().moves_setup("hello world")
        self.moves.append('fly')
dog = Superdog('Freddy')
print (dog.name)
dog.moves_setup()
print (dog.get_moves()) 

Dieses Beispiel ähnelt dem oben erläuterten. Es gibt jedoch einen Unterschied, an den super keine Argumente übergeben werden. Dieser obige Code ist in der Python 3.4-Version ausführbar.

kkk
quelle
3

In diesem Beispiel cafec_paramhandelt es sich um eine Basisklasse (übergeordnete Klasse) und abceine untergeordnete Klasse. abcruft die AWCMethode in der Basisklasse auf.

class cafec_param:

    def __init__(self,precip,pe,awc,nmonths):

        self.precip = precip
        self.pe = pe
        self.awc = awc
        self.nmonths = nmonths

    def AWC(self):

        if self.awc<254:
            Ss = self.awc
            Su = 0
            self.Ss=Ss
        else:
            Ss = 254; Su = self.awc-254
            self.Ss=Ss + Su   
        AWC = Ss + Su
        return self.Ss


    def test(self):
        return self.Ss
        #return self.Ss*4

class abc(cafec_param):
    def rr(self):
        return self.AWC()


ee=cafec_param('re',34,56,2)
dd=abc('re',34,56,2)
print(dd.rr())
print(ee.AWC())
print(ee.test())

Ausgabe

56

56

56
Khan
quelle
2

In Python 2 hatte ich mit super () nicht viel Glück. Ich habe die Antwort von jimifiki in diesem SO-Thread verwendet , um auf eine übergeordnete Methode in Python zu verweisen.. Dann habe ich meine eigene kleine Wendung hinzugefügt, die meiner Meinung nach eine Verbesserung der Benutzerfreundlichkeit darstellt (insbesondere, wenn Sie lange Klassennamen haben).

Definieren Sie die Basisklasse in einem Modul:

 # myA.py

class A():     
    def foo( self ):
        print "foo"

Importieren Sie dann die Klasse in ein anderes Modul as parent:

# myB.py

from myA import A as parent

class B( parent ):
    def foo( self ):
        parent.foo( self )   # calls 'A.foo()'
BuvinJ
quelle
2
Sie müssen class A(object): anstelle von class A(): Dann wird super () funktionieren
blndev
Ich bin mir nicht sicher, ob ich folge. Meinst du in der Definition der Klasse? Natürlich müssen Sie angeben, dass eine Klasse irgendwie einen Elternteil hat, um zu glauben, dass Sie sich auf einen Elternteil beziehen könnten! Da ich dies vor 9 Monaten gepostet habe, bin ich ein bisschen verschwommen in den Details, aber ich denke, ich meinte, die Beispiele von Arun Ghosh, Lawrence, KKK usw. sind in Py 2.x nicht anwendbar. Stattdessen ist hier eine Methode, die funktioniert und eine einfache Möglichkeit, auf die Eltern zu verweisen, damit etwas klarer wird, was Sie tun. (wie mit Super)
BuvinJ
0
class department:
    campus_name="attock"
    def printer(self):
        print(self.campus_name)

class CS_dept(department):
    def overr_CS(self):
        department.printer(self)
        print("i am child class1")

c=CS_dept()
c.overr_CS()
Maryam Mehboob
quelle
-3
class a(object):
    def my_hello(self):
        print "hello ravi"

class b(a):
    def my_hello(self):
    super(b,self).my_hello()
    print "hi"

obj = b()
obj.my_hello()
RAVIKUMAR RACHA
quelle
2
Willkommen beim Stackoverflow. Diese Frage wurde bereits vor fast zehn Jahren ausführlich beantwortet, die Antwort akzeptiert und weitgehend positiv bewertet, und Ihre Antwort fügt nichts Neues hinzu. Möglicherweise möchten Sie stattdessen versuchen, neuere (und vorzugsweise unbeantwortete) Fragen zu beantworten. Als Randnotiz gibt es im Editor eine Schaltfläche, mit der Sie die richtige Code-Formatierung anwenden können.
Bruno Desthuilliers
-24

Dies ist eine abstraktere Methode:

super(self.__class__,self).baz(arg)
user806071
quelle
15
self .__ class__ funktioniert nicht richtig mit super, da self immer die Instanz ist und seine Klasse immer die Klasse der Instanz ist. Dies bedeutet, wenn Sie super (self .__ class__ .. in einer Klasse verwenden und diese Klasse von geerbt wird, funktioniert es nicht mehr.
Xitrium
16
Verwenden Sie diesen Code NICHT, um dies zu betonen. Es besiegt den gesamten Zweck von super (), nämlich die MRO korrekt zu durchlaufen.
Eevee
1
stackoverflow.com/a/19257335/419348 sagte, warum nicht anrufen super(self.__class__, self).baz(arg).
AechoLiu