Документация по Python из super
гласит:
This is useful for accessing inherited methods that have been overridden in a class.
Есть ли смысл вызывать super().method()
в подклассе, который нет переопределяет method
?
Для меня нет, поскольку вызов self.method()
был бы эквивалентен, то есть наследование будет искать method
в суперклассах self
с использованием того же порядка разрешения методов type(self).__mro__
(заданного линеаризация C3 иерархии суперклассов self
), чем super
.
Так что для меня super
полезен в этой ситуации:
class A:
def f(self):
print("A")
class B:
pass
class C(B, A):
def f(self):
super().f()
print("C")
C().f() # prints A C
но не в этом:
class A:
def f(self):
print("A")
class B:
pass
class C(B, A):
def g(self):
super().f() # should be just self.f()
print("C")
C().g() # prints A C
(То есть ваш «бесполезный» пример на самом деле хуже, чем бесполезный, поскольку он может активно препятствовать вызову правильного метода в первую очередь.)
@chepner Да, с super().f()
в C
вы не знаете, к какому классу он будет относиться, но не с self.f()
, не так ли?
Но вы не являетесь активным пропуская реализацией с self.f()
. Вы даете type(f).f
шанс запуститься и позволяете ему решить, нужно ли ему вызывать метод, который он переопределяет.
@chepner Я думаю, ты имел в виду type(self).f
. Хорошо, я понял: если я создам подкласс D
из C
и переопределю в нем f
, вызов D.g
вызовет D.f
с self.f()
, но A.f
с super().f()
, верно?
Верно. D.g
будет разрешаться в C.g
, а super().f
, поскольку MRO — это [D, C, B, A, object]
, пропустит D.f
и разрешится в A.f
.
@chepner Хорошо. Если вы хотите написать ответ, я буду рад принять его. Итак, вопрос был таким: «Есть ли смысл в Python вызывать super().method()
в подклассе, который не переопределяет метод?» И ответ: да, если вы хотите избежать дочерних реализаций (которые, в конце концов, могут быть полезны). Если у вас есть конкретное использование, было бы еще лучше.
Как отметил @chepner, вызов super().method()
в подклассе, который не переопределяет method
, эквивалентен нет вызову self.method()
. Разница проявляется в подклассах этого подкласса, которые переопределяют method
.
Сравнивать:
class A:
def f(self):
print("A")
class B:
pass
class C(B, A):
def g(self):
super().f() # == super(C, self).f(), so lookup starts after C in type(self).__mro__
print("C")
class D(C):
def f(self):
print("D")
D().g() # prints A C, since D.__mro__ == (D, C, B, A, object)
с участием:
class A:
def f(self):
print("A")
class B:
pass
class C(B, A):
def g(self):
self.f() # lookup starts at the beginning in type(self).__mro__
print("C")
class D(C):
def f(self):
print("D")
D().g() # prints D C, since D.__mro__ == (D, C, B, A, object)
Это зависит. Помните, что в
C
вы не знаю, к какому классуsuper()
будет относиться. Это определяется во время выполнения, иself
может быть экземпляром какого-то потомкаC
, о котором вы не знаете. Класс Это может переопределитьf
.