← Назад к вопросам

Что такое MRO?

1.7 Middle🔥 141 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

MRO — Method Resolution Order

MRO (порядок разрешения методов) определяет последовательность, в которой Python ищет метод или атрибут в иерархии классов при множественном наследовании. Это критически важно для правильной работы с наследованием в Python.

Как работает MRO

Пython использует алгоритм C3 линеаризации (C3 Linearization), который гарантирует:

  1. Сохранение порядка наследования
  2. Консистентность иерархии
  3. Моноидность (соблюдение локального порядка)
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):
    pass

print(D.mro())  # [<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>]
print(D().method())  # "B" — берется из B первой

Просмотр MRO

Три способа посмотреть MRO класса:

# 1. Метод mro()
print(D.mro())
# [<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>]

# 2. Функция inspect.getmro()
import inspect
print(inspect.getmro(D))

# 3. Атрибут __mro__
print(D.__mro__)

# 4. help() функция
help(D)

super() и MRO

Функция super() использует MRO для вызова метода следующего класса в цепочке:

class Animal:
    def speak(self):
        print("Some sound")

class Dog(Animal):
    def speak(self):
        print("Woof!")
        super().speak()  # Вызовет Animal.speak()

class Puppy(Dog):
    def speak(self):
        print("Small woof!")
        super().speak()  # Вызовет Dog.speak(), который вызовет Animal.speak()

puppy = Puppy()
puppy.speak()
# Output:
# Small woof!
# Woof!
# Some sound

Проблемы при неправильном использовании

Проблема Diamond Problem (алмазная проблема):

class A:
    def method(self):
        print("A")

class B(A):
    def method(self):
        print("B")
        super().method()

class C(A):
    def method(self):
        print("C")
        super().method()

class D(B, C):
    pass

print(D.mro())  # [D, B, C, A, object]
d = D()
d.method()
# Output:
# B
# C
# A
# (A вызывается только один раз!)

Без MRO/C3 алгоритма, A был бы вызван дважды.

Практические примеры

Правильное использование super() в множественном наследовании:

class TimestampMixin:
    def save(self):
        print(f"Saving at {datetime.now()}")
        super().save()

class ValidatorMixin:
    def save(self):
        print("Validating data")
        super().save()

class Model:
    def save(self):
        print("Writing to database")

class User(ValidatorMixin, TimestampMixin, Model):
    pass

print(User.mro())
# [User, ValidatorMixin, TimestampMixin, Model, object]

user = User()
user.save()
# Output:
# Validating data
# Saving at 2026-03-22 10:15:30.123456
# Writing to database

Ошибки при нарушении MRO

Python выдаст ошибку при нарушении консистентности:

class A:
    pass

class B(A):
    pass

class C(A):
    pass

# Это вызовет ошибку!
try:
    class D(A, B):  # A должна быть после B в MRO
        pass
except TypeError as e:
    print(e)
    # TypeError: Cannot create a consistent method resolution order (MRO)

Лучшие практики

  1. Избегайте глубокой иерархии — больше 3-4 уровней часто приводит к проблемам:
# Плохо
class A: pass
class B(A): pass
class C(B): pass
class D(C): pass
class E(A, D): pass  # Сложно отследить MRO

# Хорошо
class Model: pass
class TimestampMixin: pass
class User(TimestampMixin, Model): pass
  1. Используйте mixins вместо глубокого наследования:
# Плохо
class User(Employee, Person, TimeStamped, Validatable): pass

# Хорошо
class User(TimestampMixin, ValidatorMixin, Model): pass
  1. Всегда вызывайте super() в mixins:
class Mixin:
    def method(self):
        # Сделать что-то
        super().method()  # Не забудьте!
  1. Проверяйте MRO перед множественным наследованием:
class MyClass(Base1, Base2):
    pass

print(MyClass.mro())  # Убедитесь в порядке

Вывод: MRO — это основа корректного наследования в Python. Понимание C3 алгоритма критично при работе с множественным наследованием и mixins. Используйте super() вместо явного вызова базовых классов и избегайте сложных иерархий наследования.

Что такое MRO? | PrepBro