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.

Author: Raymond Hettinger, 2008-10-21

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.

 328
Author: John Millikin,
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życie super 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

  1. Pobierz mro z typu instancji
  2. poszukaj typu, który definiuje metodę
  3. Znajdź następny Typ za pomocą metody
  4. połącz tę metodę i wywołaj ją z oczekiwanymi argumentami

UnsuperChild nie powinny mieć dostępu do InjectMe. Dlaczego wniosek nie brzmi "zawsze unikaj używania super"? 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.

 345
Author: Aaron Hall,
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:

  1. przykład linearyzacji C3 z super (duża hierarchia)
  2. Ważne zmiany zachowania pomiędzy klasami Starego i nowego stylu
  3. historia o klasach nowego stylu
 40
Author: skhalymon,
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)

 35
Author: mhawke,
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)
 21
Author: Michael Ekoka,
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. przykład drzewa super dziedziczenia

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.

 8
Author: run_the_race,
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.

 3
Author: cdude,
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 .

 3
Author: Raymond Hettinger,
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:

  1. klasy najwyższego poziomu w Twojej hierarchii muszą dziedziczyć z klasy niestandardowej jak SuperObject:
  2. 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
 2
Author: Aviad Rozenhek,
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.

 1
Author: tsh,
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.

 0
Author: dorisxx,
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