Powiedzmy ze jest roznica w MRO w Pythonie 2 vs Pythonie 3. Ale ta różnica polega nie na wersji Pythona tylko bardziej na wersji algorytmu MRO. A algorytm MRO zalezy czy jest uzyte A czy A(object).
Tutaj jest tylko C(A, B) i A oraz B ( autor moim zdaniem uzyl tego nieświadomie , niezgodnie z konwencja bez wiedzy ocb).
Zaś wracając do samych różnic w MRO:
Python 3.6.1
Kopiuj
class A:
def who_am_i(self):
print("I am a A")
class B(A):
def who_am_i(self):
print("I am a B")
class C(A):
def who_am_i(self):
print("I am a C")
class D(B,C):
def who_am_i(self):
print("I am a D")
d1 = D()
d1.who_am_i()
print(D.__mro__)
Python 3.6.1
Kopiuj
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
Python 2.7.13
Kopiuj
class A(object):
def who_am_i(self):
print("I am a A")
class B(A):
def who_am_i(self):
print("I am a B")
class C(A):
def who_am_i(self):
print("I am a C")
class D(B,C):
def who_am_i(self):
print("I am a D")
d1 = D()
d1.who_am_i()
print(D.__mro__)
Python 2.7.13
Kopiuj
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
Użycie samego A w Python 2.7 używa starego algorytmu MRO czyli przeszukiwanie nastapi w takiej kolejnosci -> D, B, A, C, A
- nie mozna tego chyba latwo sprawdzić bo brak dziedziczenia po object zabiera mozliwosc uzycia MRO.
Ale jest to DFS od lewej wgłąb.
Uzycie A(object) w Pythonie 2.7 odpala nowy algorytm MRO
Uzycie A w Pythonie 3 dziala jak A(object) w Pythonie 2.7 czyli z uzyciem nowego MRO
+
nowy algorytm MRO dziala podobnie jak stary czyli DFS od lewej wgłąb ale ma dodatkowy warunek
tj: sprawdza redundancje w tym wypadku redundancja jest przy dziedziczeniu po klasie A bo zarowno B jak i C dziedziczy po A
stad finalnie bedzie: D, B, C, A dla podanego przypadku tj: usuwa redundancje i bierze wedlug kolejnosci klasy D.
Stawiam że autor użył "błędnie" Pythona 2.x bo użycie A zamiast A(object) w wersji 2.7 jest błędem. Dlatego że należy dziedziczyć po object i używać "nowych klas".
Użycie Pythona 2.x potwierdza: print " " zamiast print("") dla Pythona 3.
Tak czy siak w przypadku autora niezależnie jakiej wersji Pythona i algorytmu MRO uzyje zawsze bedzie tak samo.
Dodatkowo różnica "nowy MRO" vs "stary MRO" jest taka że "nowy MRO" blokuje stworzenie struktury wzajemnie zależnych klas i rzuca błędem - zaś stary MRO na to zezwoli.
Kopiuj
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases Y, X
Przyklad wzajemnice zaleznych klas ( Python 2.7.13)
Kopiuj
class X(object):
def who_am_i(self):
print("I am a X")
class Y(object):
def who_am_i(self):
print("I am a Y")
class A(X, Y):
def who_am_i(self):
print("I am a A")
class B(Y, X):
def who_am_i(self):
print("I am a B")
class F(A, B):
def who_am_i(self):
print("I am a F")