← Назад к вопросам
Как реализован поиск классов в множественном наследовании в Python?
3.0 Senior🔥 111 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Поиск классов в множественном наследовании (MRO)
MRO (Method Resolution Order) — это порядок поиска методов и атрибутов в иерархии классов. Python использует алгоритм C3 Linearization для определения этого порядка.
1. История подходов
DFS (Depth-First Search) - старый подход (Python 2)
class A:
def method(self): return "A"
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
# Python 2 использовал DFS: D -> B -> A -> C -> A (неправильно!)
# A посещается дважды
C3 Linearization - новый подход (Python 3)
Питон 3 использует более умный алгоритм, который гарантирует:
- Порядок соответствует объявлению - левые родители до правых
- Родитель после детей
- Монотонность - порядок предков каждого класса сохраняется
2. Как работает C3 Linearization
Простой пример
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
print(D.mro())
# [<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>]
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
3. Использование super()
super() работает в контексте MRO:
class A:
def method(self):
print("A")
class B(A):
def method(self):
print("B")
super().method() # Идет по MRO
class C(A):
def method(self):
print("C")
super().method() # Идет по MRO
class D(B, C):
def method(self):
print("D")
super().method() # Идет по MRO
print(D.mro()) # [D, B, C, A, object]
d = D()
d.method()
# Output:
# D
# B
# C
# A
4. Diamond Problem
class Animal:
def speak(self):
print("Some sound")
class Dog(Animal):
def speak(self):
print("Woof!")
super().speak()
class Cat(Animal):
def speak(self):
print("Meow!")
super().speak()
class DogCat(Dog, Cat): # Множественное наследование
pass
print(DogCat.mro())
# [DogCat, Dog, Cat, Animal, object]
obj = DogCat()
obj.speak()
# Output:
# Woof!
# Meow!
# Some sound
C3 гарантирует, что Animal будет вызван только один раз, в конце.
5. Несовместимые порядки
class X: pass
class Y: pass
class A(X, Y): pass
class B(Y, X): pass
class C(A, B): pass # TypeError!
# TypeError: Cannot create a consistent method resolution order (MRO)
# for bases Y, X
Это происходит, когда порядки наследования противоречат друг другу.
6. Сложный пример
class A:
def who(self):
return "A"
class B(A):
def who(self):
return "B"
class C(A):
def who(self):
return "C"
class D(A):
def who(self):
return "D"
class E(B, C):
pass
class F(C, D):
pass
class G(E, F):
pass
print(G.mro())
# [G, E, B, F, C, D, A, object]
obj = G()
print(obj.who()) # "B" - первый в MRO, который реализует метод
7. Визуализация MRO
def print_mro(cls):
print(f"MRO для {cls.__name__}:")
for i, parent in enumerate(cls.mro()):
print(f" {i}: {parent}")
class Shape:
pass
class Color:
pass
class Drawable(Shape, Color):
pass
print_mro(Drawable)
# MRO для Drawable:
# 0: <class 'Drawable'>
# 1: <class 'Shape'>
# 2: <class 'Color'>
# 3: <class 'object'>
8. Django Model Mixin
class TimestampMixin:
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class AuthorMixin:
author = models.ForeignKey(User, on_delete=models.CASCADE)
class Post(TimestampMixin, AuthorMixin, models.Model):
title = models.CharField(max_length=200)
print(Post.mro())
# [Post, TimestampMixin, AuthorMixin, Model, ..., object]
9. Инструменты для анализа
# Просмотр MRO
print(MyClass.__mro__) # Кортеж
print(MyClass.mro()) # Список
# Проверка наследования
issubclass(Child, Parent)
isinstance(obj, Parent)
# Получить следующий класс в MRO
next_class = super()
# inspect модуль
import inspect
print(inspect.getmro(MyClass))
Ключевые моменты
- C3 Linearization - алгоритм поиска в MRO
- super() - идет по MRO, а не по наследованию
- Порядок наследования важен - class D(B, C) не равен class D(C, B)
- Diamond Problem решён - благодаря C3
- Несовместимые порядки приводят к ошибке - Python проверяет корректность
- MRO видно через .mro() - всегда можно посмотреть порядок
- Используй super() - не вызывай методы родителей напрямую
Это мощный механизм для правильной обработки сложных иерархий классов.