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, Bi Cgdzie każda klasa jest rodzicem jednego po nim, i a, bi codpowiednie instancje każdy.
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
Korzystanie superz metody statycznej
np. korzystanie super()z __new__()metody
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 - 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 :
# 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- podczas wywoływania, super()aby dostać się do klasy nadrzędnej, przekazujemy klasę potomną Ajako 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, gdy A.__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.
super(A, cls)
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 zainteresowania 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)
Korzystanie superz metody instancji
np. korzystanie super()z 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__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ć:
# 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- 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.
super(A, self)
3- Wywołanie super(A, self)zwraca serwer proxy, który rozwiąże zakres i zastosuje go selftak, jakby był teraz instancją klasy nadrzędnej. Nazwijmy to proxy s. Ponieważ __init__()jest to metoda instancji, wywołanie s.__init__(...)domyślnie przekaże referencję selfjako pierwszy argument do rodzica __init__().
4- aby zrobić to samo bez supermusimy 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żywanie supermetody klasowej
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- Metodę klasy można wywołać bezpośrednio z klasy i przyjmuje jako swój pierwszy parametr odwołanie 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- 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.
super(B, cls_or_subcls)
3- Połączenie super(B, cls)jest rozpatrywane w zakresie Ai dotyczy go cls. Ponieważ alternate_constructor()jest to metoda klasy, wywołanie super(B, cls).alternate_constructor(...)domyślnie przekaże referencję clsjako pierwszy argument do Awersjialternate_constructor()
super(B, cls).alternate_constructor()
4- aby zrobić to samo bez użycia super(), musisz uzyskać odniesienie do niezwiązanej wersji A.alternate_constructor()(tj. Jawnej wersji funkcji). Po prostu zrobienie tego nie zadziałałoby:
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łoby, ponieważ A.alternate_constructor()metoda przyjmuje Ajako pierwsze odwołanie niejawne odniesienie . clsPrzepuszcza tutaj będzie jego drugi argument.
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)