W tym samouczku nauczymy się kolejności rozstrzygania metod, znanej również jako MRO. Jest to podstawowa koncepcja dziedziczenia w Pythonie.
Kolejność rozwiązywania metod opisuje ścieżkę wyszukiwania klasy, która Pyton używa, aby uzyskać odpowiednią metodę w klasach zawierających wielokrotne dziedziczenie.
Wstęp
Jak wiemy, dziedziczona klasa nazywana jest podklasą lub klasą nadrzędną, natomiast klasa, która dziedziczy, nazywana jest klasą podrzędną lub podklasą. W przypadku dziedziczenia wielokrotnego klasa może składać się z wielu funkcji, dlatego do wyszukiwania kolejności wykonywania klasy bazowej używana jest technika kolejności rozstrzygania metod.
W prostych słowach: „Metoda lub atrybuty są badane w bieżącej klasie, jeśli metody nie ma w bieżącej klasie, wyszukiwanie przenosi się do klas nadrzędnych i tak dalej”. To jest przykład wyszukiwania w głąb.
Odgrywa zasadniczą rolę w dziedziczeniu wielokrotnym, gdzie tę samą metodę można znaleźć w wielu nadklasach.
Aby lepiej to zrozumieć, zobaczmy, jak możemy z niego skorzystać.
Przykład -
class A: def myname(self): print('I am a class A') class B(A): def myname(self): print('I am a class B') class C(A): def myname(self): print('I am a class C') c = C() print(c.myname())
Wyjście:
I am a class C
Wyjaśnienie -
W powyższym kodzie występuje dziedziczenie wielokrotne. Zdefiniowaliśmy trzy klasy zwane A, B i C, a te klasy mają tę samą nazwę metody moje imię(). Stworzyliśmy obiekt klasy C. Obiekt wywołał klasę C, a nie klasę, natomiast klasa C dziedziczy metodę klasy A.
Kolejność jest przestrzegana w powyższym kodzie klasa B -> klasa A. Technika ta znana jest jako MRO (kolejność rozstrzygania metod).
Rozważmy inny przykład wielokrotnego dziedziczenia.
Przykład -
class A: def myname(self): print(' I am a class A') class B(A): def myname(self): print(' I am a class B') class C(A): def myname(self): print('I am a class C') # classes ordering class D(B, C): pass d = D() d.myname()
Wyjście:
I am a class B
Wyjaśnienie -
W powyższym kodzie utworzyliśmy kolejną klasę D bez definiowania atrybutów klasy, która dziedziczyła klasę B i C. Kiedy wywołaliśmy metodę moje imię(), idzie do klasy D i szuka moje imię( ) funkcja. Ale klasa D nie ma żadnej deklaracji. W związku z tym wyszukiwanie przenosi się do klasy B, pobiera moje imię() funkcję i zwraca wynik. Wyszukiwanie odbędzie się w następujący sposób.
Class D -> Class B -> Class C -> Class A
Jeśli klasa B nie miałaby metody, wywoła metodę klasy C.
W tym przypadku sugerujemy usunięcie metody klasy B i sprawdzenie, co się stanie. Robiąc to, będziesz miał pojęcie o tym, jak działa rozpoznawanie metod.
Porządek starego i nowego stylu
W starszej wersji Pythona (2.1) możemy używać tylko starych klas, ale Pyton (2.2 i kontynuacja), możemy korzystać z nowych klas. Domyślnie Python 3 ma oryginalne (nowe) klasy. Pierwszy rodzic nowej klasy stylu dziedziczy z głównej klasy obiektu Pythona. Zobaczmy następujący przykład -
Przykład -
# Old style class class OldStyleClass: pass # New style class class NewStyleClass(object): pass
Styl deklaracji obu klas jest inny. Przy rozpoznawaniu metod klasy starego stylu postępują zgodnie z algorytmem „głębokość od lewej do prawej” (DLR), podczas gdy klasy w nowym stylu korzystają z algorytmu linearyzacji C3 podczas wykonywania dziedziczenia wielokrotnego.
Algorytm DLR
Python tworzy listę klas, wdrażając wielokrotne dziedziczenie między klasami. Lista ta służy do określenia, która metoda ma zostać wywołana przez instancje.
Możemy założyć, że działamy według nazwy, ponieważ rozpoznawanie metod będzie przeszukiwać najpierw w głąb, a następnie od lewej do prawej. Poniżej znajduje się przykład.
Przykład -
class A: pass class B: pass class C(A, B): pass class D(B, A): pass class E(C,D): pass
Najpierw algorytm będzie szukać w klasie instancji wywołanej metody. Jeśli nie zostanie znaleziony, przechodzi do pierwszych rodziców, jeśli również nie zostanie znaleziony. Przyjrzy się rodzicowi rodzica. Będzie to trwało do końca dziedziczenia klas.
W powyższym przykładzie kolejność rozstrzygania metod będzie następująca -
class D -> class B -> class A -> class C -> class A
Ale A nie może być dwukrotnie obecne, więc -
class D -> class B -> class A -> class C ->
Algorytm ten pokazuje dziwne zachowanie w tym czasie. Zobaczmy poniższy przykład.
licznik Javy
Przykład -
class A: pass class B: pass class C(A, B): pass class D(B, A): pass class E(C,D): pass
Według algorytmu DLR kolejność będzie następująca: E, C, D, B, A. W klasie C następuje zamiana klas A i B, co jest bardzo niejednoznaczne. Oznacza to, że algorytm nie zachowuje właściwości monotoniczności.
Samuele Perdoni był pierwszą osobą, która odkryła niespójność pomiędzy algorytmami MRO.
Algorytm linearyzacji C3
Algorytm linearyzacji C3 jest lepszą wersją algorytmu DLR, ponieważ usuwa niespójność. Algorytm ten ma pewne ograniczenia, które podano poniżej.
- Dzieci muszą poprzedzać swoich rodziców.
- Jeśli konkretna klasa dziedziczy z jednej lub większej liczby klas, są one zapisywane w kolejności określonej w krotce klasy bazowej.
Zasady algorytmu linearyzacji C3
- Strukturę kolejności rozstrzygania metod definiuje graf dziedziczenia.
- Użytkownik musi odwiedzić superklasę dopiero po zapoznaniu się z metodami klas lokalnych.
- Zachowaj monotoniczność
Metoda klasy Rozdzielczość metod
Python udostępnia dwa sposoby uzyskania kolejności rozwiązywania metod klasy — __mro__ atrybut lub pan() metoda. Za pomocą tych metod możemy wyświetlić kolejność metod, w jakiej są one rozwiązywane.
Rozumiemy następujący przykład.
Przykład -
class A: def myname(self): print(' I am a class A') class B(A): def myname(self): print(' I am a class B') class C(A): def myname(self): print('I am a class C') # classes ordering class D(B, C): pass # it prints the lookup order print(D.__mro__) print(C.mro())
Wyjście:
(, , , , ) [, , ]
Jak widać na powyższym wyjściu, otrzymujemy kolejność rozwiązywania metod. W ten sposób algorytm linearyzacji C3 działa w przypadku dziedziczenia wielokrotnego.