← Назад к вопросам
Что такое Method Resolution Order (MRO)?
2.0 Middle🔥 201 комментариев
#DevOps и инфраструктура#Django
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Method Resolution Order (MRO)
Что такое MRO?
Method Resolution Order (MRO) — это порядок, в котором Python ищет методы и атрибуты в иерархии наследования. Когда вы вызываете метод на объекте, Python проходит по классам в определенном порядке, пока не найдет нужный метод.
Это особенно важно при использовании множественного наследования, когда класс наследует от нескольких родителей.
1. Простое наследование (линейное)
class Animal:
def speak(self):
return "Some sound"
class Dog(Animal):
def speak(self):
return "Woof!"
class GoldenRetriever(Dog):
pass # Наследует speak от Dog
dog = GoldenRetriever()
print(dog.speak()) # "Woof!"
# MRO: [GoldenRetriever, Dog, Animal, object]
# Python ищет методы в этом порядке
print(GoldenRetriever.__mro__)
# (<class 'GoldenRetriever'>, <class 'Dog'>, <class 'Animal'>, <class 'object'>)
Порядок:
- Проверяет GoldenRetriever
- Проверяет Dog → находит speak()
- Возвращает результат
2. Множественное наследование (сложнее!)
class A:
def method(self):
return "A"
class B(A):
def method(self):
return "B"
class C(A):
def method(self):
return "C"
class D(B, C): # Наследует от B и C
pass
obj = D()
print(obj.method()) # "B"
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
Почему "B"? Потому что B указан первым в D(B, C).
3. Diamond Problem (классическая проблема)
class Animal:
def speak(self):
return "Some sound"
class Dog(Animal):
def speak(self):
return "Woof"
class Cat(Animal):
def speak(self):
return "Meow"
class Hybrid(Dog, Cat): # Наследует от Dog и Cat (оба от Animal)
pass
hybrid = Hybrid()
print(hybrid.speak()) # "Woof"
print(Hybrid.__mro__)
# (<class 'Hybrid'>, <class 'Dog'>, <class 'Cat'>, <class 'Animal'>, <class 'object'>)
Без MRO это привело бы к проблемам:
- Какой метод вызвать: Dog.speak или Cat.speak или Animal.speak?
- Animal появляется в цепочке дважды!
MRO решает это: C3 линеаризация гарантирует, что:
- Каждый класс появляется только один раз
- Родители идут в правильном порядке
- Порядок наследования сохраняется
4. C3 Linearization Algorithm
Пython использует C3 алгоритм линеаризации для вычисления MRO. Правила:
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
# Вычисление MRO для D:
# MRO(D) = D + merge(MRO(B), MRO(C), [B, C])
# MRO(B) = [B, A, object]
# MRO(C) = [C, A, object]
#
# merge([B, A, object], [C, A, object], [B, C]):
# 1. B не в хвостах других → берем B
# 2. C не в хвостах → берем C
# 3. A не в хвостах → берем A
# 4. object → берем object
#
# MRO(D) = [D, B, C, A, object]
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
5. super() и MRO
super() использует MRO для вызова методов родителя.
class Animal:
def speak(self):
print("I am an animal")
class Dog(Animal):
def speak(self):
super().speak() # Вызывает следующий в MRO
print("Woof!")
class Beagle(Dog):
def speak(self):
super().speak() # Вызывает следующий в MRO (Dog)
print("Arooo!")
beagle = Beagle()
beagle.speak()
# I am an animal
# Woof!
# Arooo!
print(Beagle.__mro__)
# (<class 'Beagle'>, <class 'Dog'>, <class 'Animal'>, <class 'object'>)
Как работает:
beagle.speak()→ Beagle.speak()super().speak()в Beagle → следующий в MRO = Dog → Dog.speak()super().speak()в Dog → следующий в MRO = Animal → Animal.speak()- Выполняется print в обратном порядке
6. Практический пример: множественное наследование с super()
class Mixin1:
def method(self):
print("Mixin1")
super().method()
class Mixin2:
def method(self):
print("Mixin2")
super().method()
class Base:
def method(self):
print("Base")
class Combined(Mixin1, Mixin2, Base):
pass
obj = Combined()
obj.method()
# Mixin1
# Mixin2
# Base
print(Combined.__mro__)
# (<class 'Combined'>, <class 'Mixin1'>, <class 'Mixin2'>, <class 'Base'>, <class 'object'>)
7. Когда MRO вызывает конфликт
class A: pass
class B(A): pass
class C(A): pass
class D(A): pass
# ❌ ОШИБКА: Inconsistent MRO
try:
class E(B, C, A, D): # A появляется и как родитель B, C, D и явно
pass
except TypeError as e:
print(e)
# Cannot create a consistent method resolution order (MRO)
# for bases B, C, A, D
# ✅ ПРАВИЛЬНО: A только один раз
class E(B, C, D): # A автоматически в MRO от родителей
pass
print(E.__mro__)
# (<class 'E'>, <class 'B'>, <class 'C'>, <class 'D'>, <class 'A'>, <class 'object'>)
8. Просмотр MRO
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
# Способ 1: __mro__ атрибут
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
# Способ 2: __mro__ как список
for cls in D.__mro__:
print(cls.__name__)
# D
# B
# C
# A
# object
# Способ 3: mro() метод
print(D.mro())
# [<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>]
9. Проблемы и решения
# ПРОБЛЕМА: Глубокое множественное наследование
class A: pass
class B(A): pass
class C(B): pass
class D(B): pass
class E(C, D): pass
class F(E): pass
print(F.__mro__)
# Сложно отследить!
# РЕШЕНИЕ: Используй composition вместо наследования
class ComponentA:
def do_something(self):
pass
class ComponentB:
def do_something_else(self):
pass
class Combined:
def __init__(self):
self.a = ComponentA()
self.b = ComponentB()
def do_all(self):
self.a.do_something()
self.b.do_something_else()
Правила MRO
- Порядок наследования важен →
class D(B, C)!=class D(C, B) - Каждый класс один раз → A появится только один раз в MRO
- Родители сохраняют порядок → MRO(B) идет перед MRO(C) в
D(B, C) - Используй super() → Для правильного обхода цепочки методов
- Избегай алмазного наследования → Используй Mixin или composition
На собеседовании
Что нужно знать:
- MRO это порядок поиска методов в иерархии наследования
- Python использует C3 линеаризацию
super()работает с MRO, а не с родительским классом- Всегда проверяй
.__mro__или.mro()когда запутался в наследовании - Избегай глубокого множественного наследования (лучше composition)