MRO в Python: почему D().f() возвращает 'B'

MRO в Python: почему D().f() возвращает 'B'

@python_quiz

Разберем этот квиз

Коротко: в примере с множественным наследованием метод ищется по порядку MRO (C3-линеаризация). Порядок для D — D → B → C → A, поэтому вызывается реализация из B.

Исходный код

python

Если выполнить этот код, на экран попадет 'B'.

Как Python ищет метод: MRO (C3)

При вызове D().f() интерпретатор смотрит, где определён метод f, обходя классы в порядке MRO (method resolution order). Python использует алгоритм C3 для множественного наследования, который учитывает:

  • локальный порядок базовых классов (в объявлении class D(B, C) — сначала B, потом C);
  • сохранение линейной упорядоченности предков (монотонность);
  • объединение MRO базовых классов с учётом локального порядка.

Для нашего примера MRO получается так:

  • D
  • B (потому что B указан первым)
  • C (следующий базовый)
  • A (общий предок обоих B и C)

Поэтому при поиске f интерпретатор найдет сначала B.f(), и именно она будет вызвана.

Проверка MRO в коде

python

Ожидаемый вывод (примерно):

python

(Конечный элемент object будет присутствовать у всех новых-стильных классов Python.)

Анализ вариантов ответа

  • Выведет 'A'

Неверно: метод A.f() переопределён в обоих подклассах B и C. Поиск до A не доходит, потому что B или C первыми могут содержать f.

  • Выведет 'B'

Обосновано MRO: B стоит перед C в списке родителей D(B, C), поэтому B.f() находится первым при поиске и вызывается.

  • Выведет 'C'

Неверно при текущем порядке наследования. Если бы класс D был объявлен как D(C, B), тогда C стоял бы первым и возвращал 'C'.

  • Ошибка MRO при создании класса D

Неверно: конфликтов в линейризации C3 для этой структуры нет, так что класса D будет создан без ошибок и корректной MRO.

Как изменить поведение

Несколько простых способов:

  • Поменять порядок базовых классов:
python
  • Вызвать метод конкретного родителя явно:
python
  • Использовать super() в переопределениях для явного прокидывания к следующему в MRO:
python

Вывод

В примере с D(B, C) метод f найден в B вследствие правил MRO (C3-линеаризация). Понимание MRO критично при работе с множественным наследованием: порядок базовых классов в объявлении влияет на то, чья реализация будет использована.

Report Page