Jaka jest różnica pomiędzy:
class Child(SomeBaseClass):
def __init__(self):
super(Child, self).__init__()
i:
class Child(SomeBaseClass):
def __init__(self):
SomeBaseClass.__init__(self)
Widziałem, że jestem super
często używany na zajęciach z jednym dziedzictwem. Rozumiem, dlaczego miałbyś używać go w wielokrotnym dziedzictwie, ale nie jestem pewien, jakie są zalety korzystania z tego w takiej sytuacji.
python
oop
inheritance
super
użytkownik25785
źródło
źródło
Co za różnica?
środki zadzwonić
SomeBaseClass
„s__init__
. podczasoznacza wywołanie powiązania
__init__
z klasy nadrzędnej, która następujeChild
w kolejności rozstrzygania metod w instancji (MRO).Jeśli instancja jest podklasą potomną, w MRO może znajdować się inny rodzic.
Wyjaśnione po prostu
Kiedy piszesz klasę, chcesz, aby inne klasy mogły z niej korzystać.
super()
ułatwia innym klasom korzystanie z klasy, którą piszesz.Jak mówi Bob Martin, dobra architektura pozwala na jak najdłuższe opóźnienie podjęcia decyzji.
super()
może włączyć tego rodzaju architekturę.Gdy inna klasa podklasuje napisaną przez ciebie klasę, może ona również dziedziczyć po innych klasach. I te klasy mogą mieć
__init__
następującą po tym__init__
na podstawie kolejności klas do rozpoznawania metod.Bez
super
ciebie prawdopodobnie kodowałbyś na stałe rodzica klasy, którą piszesz (tak jak w przykładzie). Oznaczałoby to, że nie zadzwonisz do następnego__init__
w MRO, a zatem nie będziesz mógł ponownie użyć kodu w nim.Jeśli piszesz własny kod do użytku osobistego, możesz nie dbać o to rozróżnienie. Ale jeśli chcesz, aby inni używali Twojego kodu, używanie
super
to jedna z rzeczy, która umożliwia większą elastyczność użytkownikom kodu.Python 2 kontra 3
Działa to w Python 2 i 3:
Działa to tylko w Pythonie 3:
Działa bez argumentów, przesuwając się w górę w ramce stosu i pobierając pierwszy argument do metody (zwykle
self
dla metody instancji lubcls
metody klasy - ale mogą to być inne nazwy) i znajdując klasę (np.Child
) W wolnych zmiennych (__class__
w metodzie jest sprawdzana nazwa jako zmienna o swobodnym zamknięciu).Wolę zademonstrować kompatybilność krzyżową
super
, ale jeśli używasz tylko Pythona 3, możesz wywołać go bez argumentów.Pośrednictwo z kompatybilnością do przodu
Co ci to daje? W przypadku pojedynczego dziedziczenia przykłady z pytania są praktycznie identyczne z punktu widzenia analizy statycznej. Jednak użycie
super
daje warstwę pośrednią z kompatybilnością do przodu.Kompatybilność z przyszłością jest bardzo ważna dla doświadczonych programistów. Chcesz, aby Twój kod działał przy minimalnych zmianach podczas jego zmiany. Patrząc na historię zmian, chcesz dokładnie zobaczyć, co się zmieniło, kiedy.
Możesz zacząć od pojedynczego dziedziczenia, ale jeśli zdecydujesz się dodać kolejną klasę podstawową, musisz tylko zmienić linię z podstawami - jeśli podstawy zmienią się w klasie, którą dziedziczysz (powiedzmy, że dodany jest mixin), zmienisz nic w tej klasie. Zwłaszcza w Pythonie 2 uzyskanie
super
poprawnych argumentów i poprawnych argumentów metody może być trudne. Jeśli wiesz, że używaszsuper
poprawnie z pojedynczym dziedziczeniem, to sprawia, że debugowanie jest trudniejsze.Wstrzykiwanie zależności
Inne osoby mogą używać Twojego kodu i wprowadzać rodziców do rozwiązania metody:
Załóżmy, że dodajesz kolejną klasę do swojego obiektu i chcesz wstrzyknąć klasę między Foo a Bar (do testowania lub z innego powodu):
Użycie un-super potomka nie wstrzykuje zależności, ponieważ używane dziecko na stałe zakodowało metodę, która ma zostać wywołana po swojej:
Jednak klasa z dzieckiem, które używa,
super
może poprawnie wstrzyknąć zależność:Adresowanie komentarza
Python linearyzuje skomplikowane drzewo dziedziczenia za pomocą algorytmu linearyzacji C3 w celu utworzenia metody rozstrzygania metod (MRO).
Chcemy, aby metody były wyszukiwane w tej kolejności .
Aby metoda zdefiniowana w obiekcie nadrzędnym mogła znaleźć następną w tej kolejności bez
super
, musiałaby to zrobićUnsuperChild
Ma nie mieć dostępu doInjectMe
. To onUnsuperInjector
ma dostęp doInjectMe
- a jednak nie może wywołać metody tej klasy z metody, którą dziedziczyUnsuperChild
.Obie klasy podrzędne zamierzają wywoływać metodę o tej samej nazwie, która pojawi się następnie w MRO, która może być inną klasą, o której nie wiedziała, kiedy została utworzona.
Ta, która nie
super
stosuje sztywnych kodów metody rodzica - w ten sposób ograniczyła zachowanie swojej metody, a podklasy nie mogą wprowadzać funkcjonalności do łańcucha połączeń.Ten o
super
większej elastyczności. Łańcuch wywołań metod może zostać przechwycony, a funkcjonalność wprowadzona.Możesz nie potrzebować tej funkcji, ale mogą to zrobić podklasenci twojego kodu.
Wniosek
Zawsze używaj,
super
aby odwoływać się do klasy nadrzędnej zamiast na stałe ją kodować.Zamierzamy odwoływać się do klasy nadrzędnej, która jest następna w linii, a nie konkretnie tej, z której dziedziczy dziecko.
Nieużywanie
super
może powodować niepotrzebne ograniczenia dla użytkowników Twojego kodu.źródło
list
interfejsu, powiedzmy, żedoublylinkedlist
aplikacja płynnie go wybiera. Mogę uczynić mój przykład bardziej konfigurowalnym, wprowadzającconfig.txt
i implementując łącze w czasie ładowania. Czy to dobry przykład? Jeśli tak, jak powiązać kod? Zobacz pierwszy adv DI na wiki. Gdzie można skonfigurować jakąkolwiek nową implementację? w kodzieInjectMe
klasie. Komentarze nie są jednak przeznaczone do dyskusji, więc sugeruję, aby omówić to dalej z innymi na czacie lub zadać nowe pytanie na głównej stronie.__init__
funkcją super () i funkcjami. szczególnie jeśli podpis__init__
różni się w zależności od klasy w hierarchii. Dodałem odpowiedź, która koncentruje się na tym aspekcieGrałem trochę
super()
i zdałem sobie sprawę, że możemy zmienić kolejność połączeń.Na przykład mamy następną strukturę hierarchiczną:
W tym przypadku MRO z D będzie (tylko dla Python 3):
Stwórzmy klasę, w której
super()
wywołania będą wykonywane po wykonaniu metody.Widzimy więc, że kolejność rozdzielczości jest taka sama jak w MRO. Ale kiedy wywołujemy
super()
na początku metody:Mamy inną kolejność, jest odwrócona kolejność krotki MRO.
Do lektury polecam kolejne odpowiedzi:
źródło
Czy to wszystko nie zakłada, że klasa podstawowa jest klasą w nowym stylu?
Nie działa w Pythonie 2.
class A
musi być w nowym stylu, tj .:class A(object)
źródło
Podczas wywoływania
super()
rozwiązania z wersją nadrzędną metody klasy, metody instancji lub metody statycznej chcemy przekazać bieżącą klasę, w której zakresie jesteśmy pierwszym argumentem, aby wskazać zakres nadrzędny, który próbujemy rozwiązać, i jako drugi argument będący przedmiotem zainteresowania wskazujący, do którego obiektu próbujemy zastosować ten zakres.Rozważmy hierarchii klasa
A
,B
iC
gdzie każda klasa jest rodzicem jednego po nim, ia
,b
ic
odpowiednie instancje każdy.Korzystanie
super
z metody statycznejnp. korzystanie
super()
z__new__()
metodyWyjaśnienie:
1 - chociaż zwykle
__new__()
przyjmuje się jako pierwszy param odniesienie do klasy wywołującej, nie jest on zaimplementowany w Pythonie jako metoda klasy, ale raczej metoda statyczna. Oznacza to, że odwołanie do klasy musi zostać jawnie przekazane jako pierwszy argument podczas__new__()
bezpośredniego wywoływania :2- podczas wywoływania,
super()
aby dostać się do klasy nadrzędnej, przekazujemy klasę potomnąA
jako pierwszy argument, a następnie przekazujemy odniesienie do obiektu będącego przedmiotem zainteresowania, w tym przypadku jest to odwołanie do klasy, które zostało przekazane, gdyA.__new__(cls)
zostało wywołane. W większości przypadków jest to również odniesienie do klasy podrzędnej. W niektórych sytuacjach może tak nie być, na przykład w przypadku dziedziczenia wielu generacji.3 - ponieważ ogólną zasadą
__new__()
jest metoda statyczna,super(A, cls).__new__
zwróci również metodę statyczną i w tym przypadku należy podać jawnie wszystkie argumenty, w tym odniesienie do obiektu zainteresowaniacls
.4- robienie tego samego bez
super
Korzystanie
super
z metody instancjinp. korzystanie
super()
z wewnątrz__init__()
Wyjaśnienie:
1-
__init__
to metoda instancji, co oznacza, że jako pierwszy argument przyjmuje odwołanie do instancji. Po wywołaniu bezpośrednio z instancji odwołanie jest przekazywane niejawnie, co oznacza, że nie trzeba go określać:2- podczas wywoływania
super()
wewnątrz__init__()
przekazujemy klasę potomną jako pierwszy argument, a przedmiot zainteresowania jako drugi argument, który ogólnie jest odniesieniem do instancji klasy potomnej.3- Wywołanie
super(A, self)
zwraca serwer proxy, który rozwiąże zakres i zastosuje goself
tak, jakby był teraz instancją klasy nadrzędnej. Nazwijmy to proxys
. Ponieważ__init__()
jest to metoda instancji, wywołanies.__init__(...)
domyślnie przekaże referencjęself
jako pierwszy argument do rodzica__init__()
.4- aby zrobić to samo bez
super
musimy przekazać odwołanie do instancji jawnie do wersji rodzica__init__()
.Używanie
super
metody klasowejWyjaśnienie:
1- Metodę klasy można wywołać bezpośrednio z klasy i przyjmuje jako swój pierwszy parametr odwołanie do klasy.
2- podczas wywoływania
super()
w ramach metody klasy w celu rozstrzygnięcia jej wersji nadrzędnej, chcemy przekazać bieżącą klasę podrzędną jako pierwszy argument wskazujący zakres nadrzędny, którego próbujemy rozstrzygnąć, oraz obiekt będący przedmiotem zainteresowania jako drugi argument do wskazania, do którego obiektu chcemy zastosować ten zakres, co ogólnie jest odniesieniem do samej klasy potomnej lub jednej z jej podklas.3- Połączenie
super(B, cls)
jest rozpatrywane w zakresieA
i dotyczy gocls
. Ponieważalternate_constructor()
jest to metoda klasy, wywołaniesuper(B, cls).alternate_constructor(...)
domyślnie przekaże referencjęcls
jako pierwszy argument doA
wersjialternate_constructor()
4- aby zrobić to samo bez użycia
super()
, musisz uzyskać odniesienie do niezwiązanej wersjiA.alternate_constructor()
(tj. Jawnej wersji funkcji). Po prostu zrobienie tego nie zadziałałoby:Powyższe nie zadziałałoby, ponieważ
A.alternate_constructor()
metoda przyjmujeA
jako pierwsze odwołanie niejawne odniesienie .cls
Przepuszcza tutaj będzie jego drugi argument.źródło
Wiele świetnych odpowiedzi, ale dla osób uczących się wizualnie: Po pierwsze, poznajmy argumenty do super, a potem bez.
Wyobraź sobie, że istnieje instancja
jack
utworzona z klasyJack
, która ma łańcuch dziedziczenia pokazany na zielono na zdjęciu. Powołanie:super(Jack, jack).method(...)
użyje MRO (Method Resolution Order)
jack
(jego drzewa dziedziczenia w określonej kolejności) i rozpocznie wyszukiwanieJack
. Dlaczego można zapewnić klasę nadrzędną? Cóż, jeśli zaczniemy wyszukiwanie od instancjijack
, znajdzie metodę instancji, chodzi o to, aby znaleźć metodę nadrzędną.Jeśli nie podaje się argumentów super, to tak jak pierwszy przekazany argument jest klasą
self
, a drugim przekazanym argumentem jestself
. Są one automatycznie obliczane dla Ciebie w Python3.Jednak powiedzmy, że nie chcemy używać
Jack
metody, zamiast przekazywaćJack
, moglibyśmy przejść,Jen
aby zacząć szukać metody odJen
.Przeszukuje jedną warstwę na raz (szerokość nie głębokość), na przykład gdy
Adam
iSue
oba mają odpowiednią metodą, a ten zSue
znajdzie się w pierwszej kolejności.Jeśli
Cain
iSue
oba miały wymaganą metodę,Cain
jest metoda, która zostanie nazwana pierwszą. Odpowiada to w kodzie:MRO jest od lewej do prawej.
źródło
kilka świetnych odpowiedzi tutaj, ale nie dotyczą one sposobu użycia
super()
w przypadku, gdy różne klasy w hierarchii mają różne podpisy ... szczególnie w przypadku__init__
aby odpowiedzieć na tę część i móc efektywnie korzystać
super()
, sugerowałbym przeczytanie mojej odpowiedzi super () i zmianę sygnatury metod współpracy .oto tylko rozwiązanie tego scenariusza:
przykładowe użycie:
wynik:
źródło
Jest to dość łatwe do zrozumienia.
Ok, co się teraz stanie, jeśli użyjesz
super(Child,self)
?Gdy tworzona jest instancja potomna, jej MRO (Order Resolution Order) jest w kolejności (Child, SomeBaseClass, obiekt) na podstawie dziedziczenia. (zakładamy, że SomeBaseClass nie ma innych rodziców oprócz domyślnego obiektu)
Przekazując
Child, self
,super
wyszukuje w MROself
instancji i zwraca obiekt proxy obok Childa, w tym przypadku jest to SomeBaseClass, obiekt ten następnie wywołuje__init__
metodę SomeBaseClass. Innymi słowy, jeśli taksuper(SomeBaseClass,self)
,super
zwracany jest obiekt proxyobject
W przypadku wielokrotnego dziedziczenia MRO może zawierać wiele klas, więc w zasadzie
super
pozwala zdecydować, gdzie chcesz rozpocząć wyszukiwanie w MRO.źródło
Rozważ następujący kod:
Jeśli zmienisz konstruktora
Y
naX.__init__
, otrzymasz:Ale używając
super(Y, self).__init__()
, otrzymasz:A
P
czyQ
może być nawet zaangażowany z innego pliku, który nie wiem, kiedy piszeszX
iY
. Zasadniczo nie będziesz wiedział, do czegosuper(Child, self)
będzie się odnosić podczas pisaniaclass Y(X)
, nawet podpis Y jest tak prosty, jakY(X)
. Dlatego super może być lepszym wyborem.źródło