Co robi "super" w Pythonie?
Jaka jest różnica między:
class Child(SomeBaseClass):
def __init__(self):
super(Child, self).__init__()
I:
class Child(SomeBaseClass):
def __init__(self):
SomeBaseClass.__init__(self)
Widziałem super
dość często używane w klasach z pojedynczym dziedziczeniem. Rozumiem, dlaczego używasz go w wielu dziedziczeniach, ale nie wiem, jakie są zalety korzystania z niego w tego rodzaju sytuacji.
11 answers
Korzyści płynące z super()
w dziedziczeniu jednostkowym są minimalne-w większości przypadków nie musisz kodować nazwy klasy bazowej do każdej metody, która używa jej metod nadrzędnych.
Jednak prawie niemożliwe jest użycie dziedziczenia wielokrotnego bez super()
. Obejmuje to typowe idiomy, takie jak mixiny, interfejsy, abstrakcyjne klasy itp. To rozszerza się na kod, który później rozszerza twój. Gdyby ktoś później chciał napisać klasę rozszerzającą Child
i mixin, jego kod nie zadziałałby jak należy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-21 18:24:50
Co za różnica?
SomeBaseClass.__init__(self)
Oznacza wywołanie SomeBaseClass
' s __init__
. while
super(Child, self).__init__()
Oznacza wywołanie wiązania __init__
z klasy nadrzędnej, która następuje Child
w kolejności rozwiązywania metody instancji (MRO).
Jeśli instancja jest podklasą dziecka, może istnieć inny rodzic, który pojawi się następnie w MRO.
Wyjaśnione po prostu
Kiedy piszesz klasę, chcesz, aby inne klasy mogły z niej korzystać. super()
ułatwia innym klasom wykorzystaj zajęcia, które piszesz.
Jak mówi Bob Martin, dobra architektura pozwala na odroczenie podejmowania decyzji tak długo, jak to możliwe.
super()
może włączyć tego rodzaju architekturę.
Gdy inna klasa podklasuje klasę, którą napisałeś, może ona również dziedziczyć od innych klas. I te klasy mogą mieć __init__
, który przychodzi po tym __init__
w oparciu o kolejność klas do rozwiązywania metod.
BEZ {[16] } prawdopodobnie utrudni ci to rodzic klasy, którą piszesz (tak jak w przykładzie). Oznaczałoby to, że nie wywołasz następnego __init__
w MRO, a tym samym 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życie super
jest jedną z rzeczy, która pozwala użytkownikom kodu na większą elastyczność.
Python 2 kontra 3
To działa w Pythonie 2 i 3:
super(Child, self).__init__()
To działa tylko w Pythonie 3:
super().__init__()
Działa bez argumentów przesuwając się w górę ramki stosu i pobierając pierwszy argument do metody (Zwykle {[19] } dla metody instancji lub cls
dla metody klasy - ale mogą to być inne nazwy) i znajdując klasę (np. Child
) W zmiennych wolnych (jest sprawdzana z nazwą __class__
jako zmienna swobodnego zamknięcia w metodzie).
Wolę zademonstrować cross-compatible way of using super
, ale jeśli używasz tylko Pythona 3, możesz go wywołać bez argumentów.
Indirection with Forward Compatibility
Co ci to daje? Dla pojedynczego dziedziczenia przykłady z pytania są praktycznie identyczne z punktu widzenia analizy statycznej. Jednak użyciesuper
daje warstwę indrection z kompatybilnością do przodu.
[43]}kompatybilność jest bardzo ważna dla doświadczonych programistów. Chcesz, aby Twój kod działał z minimalnymi zmianami, ponieważ zmień to. Kiedy spojrzysz na historię wersji, chcesz dokładnie zobaczyć, co się zmieniło.
Możesz zacząć od pojedynczego dziedziczenia, ale jeśli zdecydujesz się dodać kolejną klasę bazową, musisz tylko zmienić linię z bazami - jeśli bazy zmienią się w klasie, z której dziedziczysz (powiedzmy, że dodano mixin), nic nie zmienisz w tej klasie. Szczególnie w Pythonie 2, uzyskanie argumentów super
i poprawne argumenty metody mogą być trudne. Jeśli wiesz, że używasz super
poprawnie z pojedynczym dziedziczeniem, co sprawia, że debugowanie jest mniej trudne.
Dependency Injection
Inne osoby mogą użyć Twojego kodu i wprowadzić rodziców do rozwiązania metody:
class SomeBaseClass(object):
def __init__(self):
print('SomeBaseClass.__init__(self) called')
class UnsuperChild(SomeBaseClass):
def __init__(self):
print('UnsuperChild.__init__(self) called')
SomeBaseClass.__init__(self)
class SuperChild(SomeBaseClass):
def __init__(self):
print('SuperChild.__init__(self) called')
super(SuperChild, self).__init__()
Powiedzmy, że dodajesz kolejną klasę do obiektu i chcesz wprowadzić klasę między Foo i Bar (w celach testowych lub z innego powodu):
class InjectMe(SomeBaseClass):
def __init__(self):
print('InjectMe.__init__(self) called')
super(InjectMe, self).__init__()
class UnsuperInjector(UnsuperChild, InjectMe): pass
class SuperInjector(SuperChild, InjectMe): pass
Użycie un - super child nie pozwala na wstrzyknięcie zależności, ponieważ dziecko, którego używasz, zakodowało metodę do być nazwane po sobie:
>>> o = UnsuperInjector()
UnsuperChild.__init__(self) called
SomeBaseClass.__init__(self) called
Klasa z dzieckiem, która używa super
może poprawnie wprowadzić zależność:
>>> o2 = SuperInjector()
SuperChild.__init__(self) called
InjectMe.__init__(self) called
SomeBaseClass.__init__(self) called
Adresowanie komentarza
Dlaczego miałoby to być przydatne?
Python linearyzuje skomplikowane drzewo dziedziczenia za pomocą algorytmu linearyzacji C3 , aby utworzyć kolejność rozwiązywania metod (MRO).
Chcemy, aby metody były wyszukiwane w tej kolejności.
Dla metody zdefiniowany w rodzicu, aby znaleźć następny w tej kolejności bez super
, musiałby
- Pobierz mro z typu instancji
- poszukaj typu, który definiuje metodę
- Znajdź następny Typ za pomocą metody
- połącz tę metodę i wywołaj ją z oczekiwanymi argumentami
UnsuperChild
nie powinny mieć dostępu doInjectMe
. Dlaczego wniosek nie brzmi "zawsze unikaj używaniasuper
"? Czego mi brakuje tutaj?
The UnsuperChild
does not have access to InjectMe
. Jest to UnsuperInjector
, który ma dostęp do InjectMe
- a jednak nie może wywołać metody tej klasy z metody, którą dziedziczy z UnsuperChild
.
Obie klasy potomne zamierzają wywołać metodę o tej samej nazwie, która pojawia się następnie w MRO, która może być inną klasą, o której nie była świadoma, kiedy została utworzona.
Ten bez super
twardo koduje metodę rodzica - w ten sposób ogranicza zachowanie jego metody, a podklasy nie mogą wprowadzić funkcji w łańcuchu wywołań.
Ten z super
ma większą elastyczność. Łańcuch wywołania metod może być przechwytywany i wstrzykiwany.
Możesz nie potrzebować tej funkcjonalności, ale podklasery Twojego kodu mogą.
Podsumowanie
Zawsze używaj super
, aby odwoływać się do klasy nadrzędnej zamiast jej kodowania na twardo.
Masz zamiar odwołać się do klasy rodzica, który jest następny w kolejce, a nie dokładnie ten, po którym dziecko dziedziczy.
Nieużywanie {[16] } może nakładać niepotrzebne ograniczenia na użytkowników Twojego kodu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-03 14:10:11
Grałem trochę z super()
i uznałem, że możemy zmienić kolejność wywoływania.
Na przykład mamy następną strukturę hierarchii:
A
/ \
B C
\ /
D
W tym przypadku MRO z D będzie (tylko dla Pythona 3):
In [26]: D.__mro__
Out[26]: (__main__.D, __main__.B, __main__.C, __main__.A, object)
Stwórzmy klasę, w której super()
wywoła po wykonaniu metody.
In [23]: class A(object): # or with Python 3 can define class A:
...: def __init__(self):
...: print("I'm from A")
...:
...: class B(A):
...: def __init__(self):
...: print("I'm from B")
...: super().__init__()
...:
...: class C(A):
...: def __init__(self):
...: print("I'm from C")
...: super().__init__()
...:
...: class D(B, C):
...: def __init__(self):
...: print("I'm from D")
...: super().__init__()
...: d = D()
...:
I'm from D
I'm from B
I'm from C
I'm from A
A
/ ⇖
B ⇒ C
⇖ /
D
Widzimy więc, że kolejność rozdzielczości jest taka sama jak w MRO. Ale kiedy wywołujemy super()
na początku metody:
In [21]: class A(object): # or class A:
...: def __init__(self):
...: print("I'm from A")
...:
...: class B(A):
...: def __init__(self):
...: super().__init__() # or super(B, self).__init_()
...: print("I'm from B")
...:
...: class C(A):
...: def __init__(self):
...: super().__init__()
...: print("I'm from C")
...:
...: class D(B, C):
...: def __init__(self):
...: super().__init__()
...: print("I'm from D")
...: d = D()
...:
I'm from A
I'm from C
I'm from B
I'm from D
Mamy inną kolejność jest odwrócona order krotki MRO.
A
/ ⇘
B ⇐ C
⇘ /
D
Do dodatkowej lektury polecam następne odpowiedzi:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:44
Czy to wszystko nie zakłada, że klasa bazowa jest klasą nowego stylu?
class A:
def __init__(self):
print("A.__init__()")
class B(A):
def __init__(self):
print("B.__init__()")
super(B, self).__init__()
Nie będzie działać w Pythonie 2. class A
musi być nowy-styl, czyli: class A(object)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-27 17:34:27
Podczas wywoływania super()
w celu rozwiązania na wersję rodzica classmethod, instance method lub staticmethod, chcemy przekazać bieżącą klasę, w której zakresie znajdujemy się jako pierwszy argument, aby wskazać, do którego zakresu rodzica próbujemy rozwiązać, a jako drugi argument interesujący obiekt, aby wskazać, do którego obiektu próbujemy zastosować ten zakres.
Rozważmy hierarchię klasA
, B
, i C
, gdzie każda klasa jest rodzicem następującej po niej klasy, oraz a
, b
i c
odpowiednie instancje każdego z nich.
super(B, b)
# resolves to the scope of B's parent i.e. A
# and applies that scope to b, as if b was an instance of A
super(C, c)
# resolves to the scope of C's parent i.e. B
# and applies that scope to c
super(B, c)
# resolves to the scope of B's parent i.e. A
# and applies that scope to c
Używając super
ze staticmethod
Np. stosując super()
z wewnątrz metody __new__()
class A(object):
def __new__(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
return super(A, cls).__new__(cls, *a, **kw)
Wyjaśnienie:
1 - mimo że zwykle __new__()
przyjmuje jako swój pierwszy param odniesienie do klasy wywołującej, nie jest to} zaimplementowane w Pythonie jako classmethod, ale raczej staticmethod. Oznacza to, że odwołanie do klasy musi być przekazane jawnie jako pierwszy argument podczas wywołania __new__()
bezpośrednio:
# if you defined this
class A(object):
def __new__(cls):
pass
# calling this would raise a TypeError due to the missing argument
A.__new__()
# whereas this would be fine
A.__new__(A)
2 - gdy wywołujemy super()
aby dostać się do klasy rodzica, przekazujemy klasę potomną A
jako jej pierwszy argument, następnie przekazujemy odniesienie do interesującego obiektu, w tym przypadku jest to odniesienie do klasy, które zostało przekazane podczas wywołania A.__new__(cls)
. W większości przypadków jest to również odniesienie do klasy dziecięcej. W niektórych sytuacjach może nie być, na przykład w przypadku dziedziczenia wielopokoleniowego.
super(A, cls)
3 - ponieważ z reguły __new__()
jest staticmethod, super(A, cls).__new__
zwróci również staticmethod i musi być podany wszystkie argumenty jawnie, w tym odniesienie do obiektu insterest, w tym przypadku cls
.
super(A, cls).__new__(cls, *a, **kw)
4-robienie tego samego bez super
class A(object):
def __new__(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
return object.__new__(cls, *a, **kw)
Użycie {[23] } z metodą instancji
Np. używając super()
od wewnątrz __init__()
class A(object):
def __init__(self, *a, **kw):
# ...
# you make some changes here
# ...
super(A, self).__init__(*a, **kw)
Wyjaśnienie:
1- __init__
jest metodą instancyjną, co oznacza, że jako pierwszy argument przyjmuje odniesienie do instancji. Kiedy wywołana bezpośrednio z instancji, Referencja jest przekazywana niejawnie, tzn. nie trzeba jej określać:
# you try calling `__init__()` from the class without specifying an instance
# and a TypeError is raised due to the expected but missing reference
A.__init__() # TypeError ...
# you create an instance
a = A()
# you call `__init__()` from that instance and it works
a.__init__()
# you can also call `__init__()` with the class and explicitly pass the instance
A.__init__(a)
2 - wywołując super()
wewnątrz __init__()
przekazujemy klasę potomną jako pierwszy argument, a obiekt zainteresowania jako drugi argument, który ogólnie jest odniesieniem do instancji klasy potomnej.
super(A, self)
3-wywołanie super(A, self)
zwraca serwer proxy, który rozwiąże zakres i zastosuje go do self
tak, jakby był teraz instancją klasy nadrzędnej. Nazwijmy to proxy s
. Ponieważ __init__()
jest metodą instancyjną, wywołanie s.__init__(...)
domyślnie przekaże odwołanie self
jako pierwszy argument do __init__()
rodzica.
4-Aby zrobić to samo bez super
, musimy przekazać odwołanie do instancji jawnie do wersji rodzica __init__()
.
class A(object):
def __init__(self, *a, **kw):
# ...
# you make some changes here
# ...
object.__init__(self, *a, **kw)
Używając super
Z klasą
class A(object):
@classmethod
def alternate_constructor(cls, *a, **kw):
print "A.alternate_constructor called"
return cls(*a, **kw)
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
return super(B, cls).alternate_constructor(*a, **kw)
Wyjaśnienie:
1-klasa może być wywołana bezpośrednio z klasy i przyjmuje jako pierwszy parametr odniesienie do klasy.
# calling directly from the class is fine,
# a reference to the class is passed implicitly
a = A.alternate_constructor()
b = B.alternate_constructor()
2 - gdy wywołujemy super()
wewnątrz klasy, aby rozwiązać jej wersję rodzica, chcemy przekazać bieżącą klasę potomną jako pierwszy argument wskazujący, do którego zakresu rodzica próbujemy rozwiązać, a obiekt zainteresowania jako drugi argument wskazujący, do którego obiektu chcemy zastosować ten zakres, co ogólnie jest odniesieniem do samej klasy potomnej lub jednej z jej podklas.
super(B, cls_or_subcls)
3-wywołanie super(B, cls)
rozwiązuje się w zakresie A
i stosuje go do cls
. Ponieważ alternate_constructor()
jest klasą, wywołanie super(B, cls).alternate_constructor(...)
domyślnie przekaże referencję cls
jako pierwszy argument do A
' s version of alternate_constructor()
super(B, cls).alternate_constructor()
4-Aby zrobić to samo bez użycia super()
, musisz uzyskać odniesienie do unbound wersji A.alternate_constructor()
(tj. jawnej wersji funkcji). Po prostu to nie zadziała: {]}
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
return A.alternate_constructor(cls, *a, **kw)
Powyższe nie zadziała, ponieważ metoda A.alternate_constructor()
przyjmuje implicite odniesienie do A
jako pierwszy argument. / Align = "left" /
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
# first we get a reference to the unbound
# `A.alternate_constructor` function
unbound_func = A.alternate_constructor.im_func
# now we call it and pass our own `cls` as its first argument
return unbound_func(cls, *a, **kw)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-07 17:33:28
Wiele świetnych odpowiedzi, ale dla wizualnych uczniów: Po pierwsze pozwala zbadać z argumentami do super, a następnie bez.
Wyobraź sobie, że istnieje instancja jack
utworzona z klasy Jack
, która ma łańcuch dziedziczenia pokazany na Zielono na obrazku. Powołanie:
super(Jack, jack).method(...)
Użyje MRO (Method Resolution Order) z jack
(drzewo dziedziczenia w określonej kolejności) i rozpocznie wyszukiwanie od Jack
. Dlaczego można zapewnić klasę rodzica? Cóż, jeśli rozpocznij wyszukiwanie od instancji jack
, znajdzie metodę instancji, chodzi o to, aby znaleźć jej metodę rodzica.
Jeśli nie podajemy argumentów do super, to tak jak pierwszy argument przekazywany w jest klasą self
, a drugi argument przekazywany w to self
. Są one automatycznie obliczane dla Ciebie w Python3.
Jednak powiedzmy, że nie chcemy używać metody Jack
, zamiast przekazywać w Jack
, możemy przekazać w Jen
, aby rozpocząć wyszukiwanie w górę dla metody z Jen
.
Przeszukuje jedną warstwę na raz (szerokość nie głębokość), np. jeśli Adam
i Sue
obie mają wymaganą metodę, ta z Sue
zostanie znaleziona pierwsza.
Jeśli Cain
i Sue
obie miały wymaganą metodę, metoda {16]} zostanie wywołana jako pierwsza.
Odpowiada to w kodzie:
Class Jen(Cain, Sue):
MRO jest od lewej do prawej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-24 17:25:47
W przypadku dziedziczenia wielokrotnego, Zwykle chcesz wywołać inicjalizatory obojga rodziców, a nie tylko pierwszego. Zamiast zawsze używać klasy bazowej, super() znajduje klasę następną w metodzie Resolution Order( MRO) i zwraca bieżący obiekt jako instancję tej klasy. Na przykład:
class Base(object):
def __init__(self):
print("initializing Base")
class ChildA(Base):
def __init__(self):
print("initializing ChildA")
Base.__init__(self)
class ChildB(Base):
def __init__(self):
print("initializing ChildB")
super().__init__()
class Grandchild(ChildA, ChildB):
def __init__(self):
print("initializing Grandchild")
super().__init__()
Grandchild()
Wyniki w
initializing Grandchild
initializing ChildA
initializing Base
Zastąpienie Base.__init__(self)
przez super().__init__()
daje
initializing Grandchild
initializing ChildA
initializing ChildB
initializing Base
Zgodnie z życzeniem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-31 22:31:49
Super () w skrócie
- każda instancja Pythona ma klasę, która go utworzyła.
- każda klasa w Pythonie ma łańcuch klas przodków.
- metoda wykorzystująca super() deleguje pracę do następnego przodka w łańcuchu dla klasy instancji.
Przykład
Ten mały przykład obejmuje wszystkie interesujące przypadki:]}class A:
def m(self):
print('A')
class B(A):
def m(self):
print('B start')
super().m()
print('B end')
class C(A):
def m(self):
print('C start')
super().m()
print('C end')
class D(B, C):
def m(self):
print('D start')
super().m()
print('D end')
Dokładna kolejność wywołań określona przez instancję, z której wywołana jest metoda:
>>> a = A()
>>> b = B()
>>> c = C()
>>> d = D()
Na przykład a , nie ma super połączenia:
>>> a.m()
A
Na przykład b , łańcuch przodków to B -> A -> object
:
>>> type(b).__mro__
(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
>>> b.m()
B start
A
B end
Na przykład c , łańcuch przodków to C -> A -> object
:
>>> type(c).__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
>>> b.m()
C start
A
C end
Na przykład d , łańcuch przodków jest bardziej interesujący D -> B -> C -> A -> object
:
>>> type(d).__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
>>> d.m()
D start
B start
C start
A
C end
B end
D end
Więcej informacji
Po odpowiedzi na pytanie " co robi super w Pythonie?", następne pytanie brzmi, jak skutecznie go wykorzystać. Zobacz ten poradnik krok po kroku lub ten 45 minutowy film .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-20 19:33:51
Kilka świetnych odpowiedzi tutaj, ale nie zajmują się jak używać super()
w przypadku, gdy różne klasy w hierarchii mają różne sygnatury ... szczególnie w przypadku __init__
Aby odpowiedzieć na tę część i móc efektywnie wykorzystać super()
proponuję przeczytać moją odpowiedź super() I zmienić sygnaturę metod kooperacyjnych.
Oto rozwiązanie tego scenariusza:
- klasy najwyższego poziomu w Twojej hierarchii muszą dziedziczyć z klasy niestandardowej jak
SuperObject
:- Jeśli klasy mogą przyjmować różne argumenty, zawsze przekaż wszystkie otrzymane argumenty do funkcji super jako argumenty słów kluczowych i zawsze Zaakceptuj
**kwargs
.
class SuperObject:
def __init__(self, **kwargs):
print('SuperObject')
mro = type(self).__mro__
assert mro[-1] is object
if mro[-2] is not SuperObject:
raise TypeError(
'all top-level classes in this hierarchy must inherit from SuperObject',
'the last class in the MRO should be SuperObject',
f'mro={[cls.__name__ for cls in mro]}'
)
# super().__init__ is guaranteed to be object.__init__
init = super().__init__
init()
Przykładowe użycie:
class A(SuperObject):
def __init__(self, **kwargs):
print("A")
super(A, self).__init__(**kwargs)
class B(SuperObject):
def __init__(self, **kwargs):
print("B")
super(B, self).__init__(**kwargs)
class C(A):
def __init__(self, age, **kwargs):
print("C",f"age={age}")
super(C, self).__init__(age=age, **kwargs)
class D(B):
def __init__(self, name, **kwargs):
print("D", f"name={name}")
super(D, self).__init__(name=name, **kwargs)
class E(C,D):
def __init__(self, name, age, *args, **kwargs):
print( "E", f"name={name}", f"age={age}")
super(E, self).__init__(name=name, age=age, *args, **kwargs)
E(name='python', age=28)
Wyjście:
E name=python age=28
C age=28
A
D name=python
B
SuperObject
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-22 11:26:05
Rozważ następujący kod:
class X():
def __init__(self):
print("X")
class Y(X):
def __init__(self):
# X.__init__(self)
super(Y, self).__init__()
print("Y")
class P(X):
def __init__(self):
super(P, self).__init__()
print("P")
class Q(Y, P):
def __init__(self):
super(Q, self).__init__()
print("Q")
Q()
Jeśli zmienisz konstruktor Y
na X.__init__
, otrzymasz:
X
Y
Q
Ale używając super(Y, self).__init__()
, otrzymasz:
X
P
Y
Q
I P
lub Q
mogą być nawet zaangażowane z innego pliku, którego nie wiesz, kiedy piszesz X
i Y
. Więc, w zasadzie, nie będziesz wiedział, do czego super(Child, self)
będzie się odwoływać, gdy piszesz class Y(X)
, nawet podpis Y jest tak prosty, jak Y(X)
. Dlatego super może być lepszym wyborem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-17 13:55:34
class Child(SomeBaseClass):
def __init__(self):
SomeBaseClass.__init__(self)
Jest to dość łatwe do zrozumienia.
class Child(SomeBaseClass):
def __init__(self):
super(Child, self).__init__()
Ok, co się teraz stanie, jeśli użyjesz super(Child,self)
?
Kiedy instancja potomna jest tworzona, jej MRO (Method Resolution Order) jest w kolejności (Child, SomeBaseClass, object) w oparciu o dziedziczenie. (Załóżmy, że SomeBaseClass nie ma innych rodziców, z wyjątkiem obiektu domyślnego)
By passing Child, self
, super
wyszukuje w MRO instancji self
i zwraca obiekt proxy obok obiektu Child, w tym przypadku jest to SomeBaseClass, obiekt ten wywołuje metodę __init__
z SomeBaseClass. Innymi słowy, jeśli jest to super(SomeBaseClass,self)
, obiekt proxy, który zwraca super
, będzie to object
Dla dziedziczenia wielu, MRO może zawierać wiele klas, więc zasadniczo super
pozwala zdecydować, gdzie chcesz rozpocząć wyszukiwanie w MRO.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-27 17:55:54