2016-12-28 7 views
1

Ich habe gerade etwas mit Mehrfachvererbung in Python versucht. Ich komme mit diesemPython mehrfache Vererbung, Aufruf Basisklasse Funktion

class ParentOne: 
    def foo(self): 
     print("ParentOne foo is called") 

class ParentTwo: 
    def foo(self): 
     print("ParentTwo foo is called") 

class Child(ParentOne, ParentTwo): 

    # how is this working 
    def call_parent_two_foo(self): 
     super(ParentOne, self).foo() 

    # This does not work 
    def call_parent_foo(self): 
     super(ParentTwo, self).foo() 

    def call_super_foo(self): 
     super(Child, self).foo() 

    def foo(self): 
     print("Child foo is called") 


if __name__ == "__main__": 
    child = Child() 
    child.foo() 
    child.call_super_foo() 
    child.call_parent_two_foo() 

    # child.call_parent_foo() #This gives the below error 
    # super(ParentTwo, self).foo() 
    # AttributeError: 'super' object has no attribute 'foo' 

und es gibt die folgende Ausgabe

Child foo is called 
ParentOne foo is called 
ParentTwo foo is called 

ich verwirrt bin immer wie Aufruf von super(ParentOne, self).foo() in diesem Fall ausgewertet wird. Nach meinem Verständnis ParentOne Klasse hat keine Ahnung von den Methoden und Eigenschaften von ParentTwo Klasse. Wie funktioniert Super bei Mehrfachvererbung?

Antwort

3

Python erstellt eine Methodenauflösungsreihenfolge (MRO), wenn es eine Klasse erstellt. Die MRO ist immer linear. Wenn Python kein lineares MRO erstellen kann, wird ValueError ausgelöst. In diesem Fall Ihre MRO sieht wahrscheinlich wie:

Child -> ParentOne -> ParentTwo -> object 

Nun, wenn Python ein super(cls, self) sehen ist, sieht es im Grunde bei self und die MRO herausfindet. Es verwendet dann cls, um festzustellen, wo wir gerade in der MRO sind und schließlich gibt es ein Objekt zurück, das an die nächste Klasse in der MRO delegiert. In diesem Fall würde also ein super(Child, self) Aufruf ein Objekt zurückgeben, das an ParentOne delegiert. Eine super(ParentOne, self) Klasse würde ein Objekt zurückgeben, das an ParentTwo delegiert. Schließlich würde ein super(ParentTwo, self) Anruf an object delegieren. Mit anderen Worten, können Sie denken super als schicke Version des folgenden Codes:

def kinda_super(cls, self): 
    mro = inspect.getmro(type(self)) 
    idx = mro.index(cls) 
    return Delegate(mro[idx + 1]) # for a suitably defined `Delegate` 

Beachten Sie, dass seit super(ParentTwo, self) einen „Delegate“ zu object zurückgibt, können wir sehen, warum Sie ein AttributeError bekommen, wenn Sie versuchen, super(ParentTwo, self).foo() - Insbesondere ist der Grund, weil object keine foo Methode hat.

+0

Gibt es einen Weg, um zu sehen/bekommen MRO –

+0

@AnuragSharma - 'inspect.getmro' es dir geben sollte. IIRC, können Sie auch über das magische Attribut "__mro__" darauf zugreifen. – mgilson

0

Sie können Child(ParentOne, ParentTwo) als zwei separate Vererbungen innerhalb einer Kette verstehen: Child(ParentOne(ParentTwo)). Eigentlich erbt ParentOne nicht ParentTwo, sie sind zwei separate Klassen, aber die Methode super funktioniert so, als gäbe es eine Kette von Vererbungen (nur im Fall von Mehrfachvererbung). Ich mag dieses Beispiel besser zu verstehen, was los ist (für Python 3.x):

class P: 
    def m(self): 
     print("P") 


class A(P): 
    def m(self): 
     super().m() # -> B, if we inherit like C(A, B) 
     print("A") 


class B(P): 
    def m(self): 
     super().m() # -> P, if we inherit like C(A, B) 
     print("B") 


class C(A, B): 
    def m(self): 
     super().m() # -> A 
     print("C") 
     A.m(self) 
     B.m(self) 


c = C() 
c.m() 

Er hält auch einen Fall, wenn zwei Eltern eine Basisklasse erben. Das Skript oben druckt:

P 
B 
A 
C 
P 
B 
A 
P 
B 
Verwandte Themen