2012-04-05 8 views
6

Vor allem muss ich mich entschuldigen, dass ich keinen besseren Titel habe. Fühlen Sie sich frei, es zu ändern, wenn Sie eine passendere finden.Python-Diamant-Vererbung und die Verwendung von super() in den Eltern der abgeleiteten Klasse

Grundsätzlich wurde ich durch das Verhalten von Pythons mehrfacher Vererbung gestört. In meiner previous SO question wurde ich angewiesen, Python's C3 MRO zu lesen. Das hilft mir wirklich, die Mehrfachvererbung in Python besser zu verstehen. Gerade als ich dachte, ich hätte es begriffen, stieß ich auf das folgende Szenario, von dem ich keinen Sinn zu haben glaube.

class UltimateBase(object): 
    def check(self): 
     print 'base check' 

class AMixin1(UltimateBase): 
    def check(self): 
     print 'check A' 

class BMixin1(UltimateBase): 
    def check(self): 
     print 'check B' 

class CMixin1(UltimateBase): 
    def check(self): 
     print 'check C' 

class AMixin2(UltimateBase): 
    def check(self): 
     print 'check A' 
     return super(AMixin2, self).check() 

class BMixin2(UltimateBase): 
    def check(self): 
     print 'check B' 
     return super(BMixin2, self).check() 

class CMixin2(UltimateBase): 
    def check(self): 
     print 'check C' 
     return super(CMixin2, self).check() 

class MyView1(AMixin1, BMixin1, CMixin1): 
    pass 

class MyView2(AMixin2, BMixin2, CMixin2): 
    pass 

class MyView3(AMixin1, BMixin2, CMixin2): 
    pass 

class MyView4(AMixin2, BMixin1, CMixin2): 
    pass 

class MyView5(AMixin2, BMixin2, CMixin1): 
    pass 

class MyView6(AMixin1, BMixin1, CMixin2): 
    pass 

class MyView7(AMixin1, BMixin2, CMixin1): 
    pass 

class MyView8(AMixin2, BMixin1, CMixin1): 
    pass 

myview1 = MyView1() 
myview2 = MyView2() 
myview3 = MyView3() 
myview4 = MyView4() 
myview5 = MyView5() 
myview6 = MyView6() 
myview7 = MyView7() 
myview8 = MyView8() 

myview1.check() 
print '------------------------' 
myview2.check() 
print '------------------------' 
myview3.check() 
print '------------------------' 
myview4.check() 
print '------------------------' 
myview5.check() 
print '------------------------' 
myview6.check() 
print '------------------------' 
myview7.check() 
print '------------------------' 
myview8.check() 
print '------------------------' 

Ausgänge:

check A 
------------------------ 
check A 
check B 
check C 
base check 
------------------------ 
check A 
------------------------ 
check A 
check B 
------------------------ 
check A 
check B 
check C 
------------------------ 
check A 
------------------------ 
check A 
------------------------ 
check A 
check B 
------------------------ 

Ich kann ein Muster verfolgen auf der Basis der Ausgänge zu beobachten, aber es stört mich nicht zu verstehen, die Gründe für dieses Ergebnis.

Ich habe Fragen, wie zum Beispiel, warum tut myview2.check() return

check A 
check B 
check C 
base check 

nicht

check A 
base check 

Es scheint mir, dass ich ein Schlüsselstück über Mehrfachvererbung bin fehlt. Bitte füllen Sie die Lücke für mich aus.

Antwort

4

Wenn Sie myview2.check() aufrufen, durchläuft es Geschwister und ruft dann die Basisklasse auf. Immer wenn einer dieser Traversals auf AMixin1, BMixin1 oder CMixin1 trifft, stoppt es, da diese Klassen super(..., self).check() nicht aufrufen.

Wie Benn darauf hinweist, ist dies in der official Python documentation beschrieben. Und wenn Sie darüber nachdenken, muss es so ziemlich funktionieren. Unterklassen gehen davon aus, dass die Basisklassenmethode nicht aufgerufen wird, bevor die Unterklasse super() aufruft. Wenn es (oder, schlimmer noch, wenn es von der Reihenfolge abhängt, in der seine Geschwister aufgeführt sind), macht es sehr schwierig, damit umzugehen.

+0

Danke Chris. Das ist eher kontraintuitiv. Aus dem Aussehen des Ergebnisses wird das 'check()' des gemeinsamen Vorfahren nicht aufgerufen, wenn nicht alle Eltern 'super()' nennen. Gibt es Literatur darüber? – tamakisquare

+1

Anstatt eine weitere Antwort hinzuzufügen, die meistens dasselbe sagt, verlinke ich einfach die Dokumentation von 'super()', die in diesem Fall die Magie macht: [Official Python Docs] (http: //docs.python. org/library/functions.html? highlight = super # super). Der Schlüssel dort ist, dass es Eltern _or Geschwister _ von 'Art' für kooperative mehrfache Vererbung nennt. – Benn

+0

@Benn - Das ist genau das letzte Stück, das ich für mein Problem brauche. Ich danke dir sehr. – tamakisquare

1

Versucht, meinen Kopf um die gleiche Frage zu bekommen. Ich fand den folgenden Code dazu beigetragen, das Problem zu vereinfachen: (. Im Grunde genommen, wenn alle super s für eine Klasse getroffen wurden, wird diese Klasse genannt)

class A: 
    def f(self): 
    print("............A: the common base of B and C") 

class B(A): 
    def f(self): 
    print("........B: the left base of D") 
    super().f() 

class C(A): 
    def f(self): 
    print("........C: the right base of D") 
    super().f() 

class D(B,C): 
    def f(self): 
    print("....D: the top class") 
    super().f() 

d = D() 

d.f() 

Ausgang:

....D: the top class 
........B: the left base of D 
........C: the right base of D 
............A: the common base of B and C 

Try Online