rogerCopy
@rogerCopy

Почему порядок вызова методов в суперклассах именно такой?

Господа, не откажите в любезности. Почему у класса SubClass super().call_me() выполняется 2 раза? Он выполняется столько, сколько суперклассов наследует класс?
Читаю книжку, такой код:
class BaseClass:
    num_base_calls = 0
    
    def call_me(self):
        print("Calling method on Base Class")
        self.num_base_calls += 1
        
class LeftSubclass(BaseClass):
    num_left_calls = 0
    
    def call_me(self):
        super().call_me()
        print("Calling method on Left Subclass")
        self.num_left_calls += 1

class RightSubclass(BaseClass):
    num_right_calls = 0
    
    def call_me(self):
        super().call_me()
        print("Calling method on Right Subclass")
        self.num_right_calls += 1

class SubClass(LeftSubclass, RightSubclass):
    num_sub_calls = 0
    
    def call_me(self):
        super().call_me()
        print("Calling method on Subclass")
        self.num_sub_calls += 1

s = SubClass()
s.call_me()


Результат:
Calling method on Base Class
Calling method on Right Subclass
Calling method on Left Subclass
Calling method on Subclass
[Finished in 0.1s]


Я так понимаю, что тут порядок принтов определяет MRO?
Правильно ли я разобрался: порядок MRO тут такой:
1. при вызове указанного метода у экземпляра s сперва происходит поиск среди его суперклассов справа налево, т.о. вызов метода у первого справа суперкласса - RightSubclass, super().call_me() которого вызывает этот метод своего суперкласса - BaseClass, происходит print("Calling method on Base Class"), потом выполняется print("Calling method on Right Subclass")
3. s.call_me() опять вызывает super().call_me() - теперь у второго найденного справа налево, т.е. LeftSubClass - который тоже наследуется от того же BaseClass. Но т.к. последний уже есть в МРО, он "вычеркивается" из МРО, и выполняется print("Calling method on Left Subclass"), а потом print("Calling method on Subclass")

Но в книжке написано, что сперва метод ищется в первом слева классе:
5e8b369a87415763411629.png
  • Вопрос задан
  • 107 просмотров
Пригласить эксперта
Ответы на вопрос 1
@Zveridze
Не совсем так.
В современных версиях применяется алгоритмы линеаризации S3.

Почему так:
Алгоритм поиска слева направо в глубину применялся только в старых версиях Питона. С версии 2.3 в Питоне появился базовый класс object, от которого было рекомендовалось наследовать все пользовательские классы. А с версии 3 старые классы отменили, теперь все классы исходят по дефолту из object. Это привело к проблеме ромбовидного наследования.
Ромбовидное наследование - ситуация в которой предки (LeftClass, RightClass) класса (SubClass) наследуются от общего класса (BaseClass).

Как в Питоне решается данная проблема:
Для каждого класса строится модель линеаризации основываясь на алгоритме S3. Результат работы алгоритмы можно посмотреть при помощи вызова Class.__mro___.
То есть, на основании результата работы данного алгоритмы, у вас сначала метод будет искаться в LeftClass, потом в RightClas, потом в BaseClass.

Вот, например, отличная статья где очень подробно рассмотрен данный алгоритм https://habr.com/ru/post/62203/
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
12 мая 2024, в 09:54
15000 руб./за проект
12 мая 2024, в 09:48
15000 руб./за проект
12 мая 2024, в 00:31
200000 руб./за проект