Вызов super().method() в подклассе, который не переопределяет метод

Документация по 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

Это зависит. Помните, что в C вы не знаю, к какому классу super() будет относиться. Это определяется во время выполнения, и self может быть экземпляром какого-то потомка C, о котором вы не знаете. Класс Это может переопределить f.

chepner 29.05.2019 21:00

(То есть ваш «бесполезный» пример на самом деле хуже, чем бесполезный, поскольку он может активно препятствовать вызову правильного метода в первую очередь.)

chepner 29.05.2019 21:03

@chepner Да, с super().f() в C вы не знаете, к какому классу он будет относиться, но не с self.f(), не так ли?

Maggyero 29.05.2019 21:06

Но вы не являетесь активным пропуская реализацией с self.f(). Вы даете type(f).f шанс запуститься и позволяете ему решить, нужно ли ему вызывать метод, который он переопределяет.

chepner 29.05.2019 21:07

@chepner Я думаю, ты имел в виду type(self).f. Хорошо, я понял: если я создам подкласс D из C и переопределю в нем f, вызов D.g вызовет D.f с self.f(), но A.f с super().f(), верно?

Maggyero 29.05.2019 21:23

Верно. D.g будет разрешаться в C.g, а super().f, поскольку MRO — это [D, C, B, A, object], пропустит D.f и разрешится в A.f.

chepner 29.05.2019 21:26

@chepner Хорошо. Если вы хотите написать ответ, я буду рад принять его. Итак, вопрос был таким: «Есть ли смысл в Python вызывать super().method() в подклассе, который не переопределяет метод?» И ответ: да, если вы хотите избежать дочерних реализаций (которые, в конце концов, могут быть полезны). Если у вас есть конкретное использование, было бы еще лучше.

Maggyero 29.05.2019 21:33
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
7
438
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как отметил @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)

Другие вопросы по теме