Перейти к содержанию

232 уроков, 16 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 18 из 20 Средний 35 мин 140 XP

Множественное наследование и миксины

Python разрешает классу нескольких родителей — и сразу отвечает на вопрос «чей метод наследовать» через линейный порядок MRO. Разберём миксины как безопасный способ множественного наследования, алмазную проблему и кооперативный super().

Редакция Питоники

Наследование от одного родителя вы уже знаете из урока 7. Python идёт дальше: класс может перечислить несколько родителей — class Book(JSONMixin, ReprMixin). В чистом виде это быстрая дорога к путанице «чей метод победил», поэтому на практике множественное наследование применяют в особом стиле: через миксины — классы-добавки поведения без своего состояния. Соберём пару таких миксинов и посмотрим, как Python разрешает конфликты имён.

Миксин: добавка поведения

JSONMixin и ReprMixin — поведение без состояния
import json

class JSONMixin:
    def to_json(self):
        return json.dumps(self.__dict__, ensure_ascii=False)

class ReprMixin:
    def __repr__(self):
        fields = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{type(self).__name__}({fields})"

class Book(JSONMixin, ReprMixin):
    def __init__(self, title, author):
        self.title = title
        self.author = author

b = Book("Война и мир", "Толстой")
print(b)
print(b.to_json())
Вывод
Book(title='Война и мир', author='Толстой')
{"title": "Война и мир", "author": "Толстой"}

Алмазная проблема и порядок MRO

ромб: чей метод победит
class Base:
    def greet(self):
        return "привет от Base"

class Left(Base):
    def greet(self):
        return "привет от Left"

class Right(Base):
    def greet(self):
        return "привет от Right"

class Child(Left, Right):
    pass

print(Child().greet())
print([cls.__name__ for cls in Child.__mro__])
Вывод
привет от Left
['Child', 'Left', 'Right', 'Base', 'object']
ПриёмЧто даёт
МиксинКласс-добавка без своего __init__ и полей: JSONMixin даёт to_json(), ReprMixin — аккуратный __repr__
Порядок родителейМиксины первыми, базовый класс последним: class Book(JSONMixin, ReprMixin) — методы миксинов главнее
MRO (__mro__)Линейный порядок поиска методов; в алмазе Child ищет по цепочке Child → Left → Right → Base
Кооперативный super()Каждый класс в цепочке вызывает super().__init__(**kwargs), и все инициализаторы срабатывают по MRO

Кооперативный super()

все классы цепочки срабатывают по одному запуску
class Logger:
    def __init__(self, **kwargs):
        print("Logger настраивает журнал")
        super().__init__(**kwargs)

class Saver:
    def __init__(self, **kwargs):
        print("Saver готовит хранилище")
        super().__init__(**kwargs)

class Service(Logger, Saver):
    def __init__(self):
        print("Service запускается")
        super().__init__()

Service()
Вывод
Service запускается
Logger настраивает журнал
Saver готовит хранилище
Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

class Base:
    def who(self):
        return "base"

class Left(Base):
    def who(self):
        return "left"

class Right(Base):
    def who(self):
        return "right"

class Child(Left, Right):
    pass

print(Child().who())
class LoudMixin:
    def loud(self):
        return self.sound().upper() + "!"

class Frog:
    def sound(self):
        return "ква"

class LoudFrog(LoudMixin, Frog):
    pass

print(LoudFrog().loud())
class A:
    def __init__(self, **kw):
        super().__init__(**kw)
        self.tag = "A"

class B(A):
    def __init__(self, **kw):
        super().__init__(**kw)
        self.tag += "B"

class C(A):
    def __init__(self, **kw):
        super().__init__(**kw)
        self.tag += "C"

class D(B, C):
    def __init__(self):
        super().__init__()

print(D().tag)
Проверь себя
0 / 6

1. Как Python ищет метод у класса с несколькими родителями?

2. Что такое миксин?

3. Куда приводит super() из класса Left при иерархии Child(Left, Right)?

4. Что даёт кооперативный вызов super().__init__(**kwargs) в каждом классе цепочки?

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

6. Когда множественное наследование — плохой выбор?

Карточки терминов
Запомнено: 0 / 7
Практика

Создайте миксин UpperMixin с методом loud(), возвращающим self.sound().upper() + "!". Опишите класс Duck со методом sound(), возвращающим «кря», и класс LoudDuck(UpperMixin, Duck). Выведите результат LoudDuck().loud().

practice.py
Вопросы и ответы по уроку

Что такое множественное наследование в Python?

Возможность класса перечислить несколько родителей: class Book(JSONMixin, ReprMixin). Python ищет методы по линейному порядку MRO — его можно увидеть в атрибуте __mro__. На практике множественное наследование применяют в форме миксинов: небольших классов-добавок поведения.

Урок 18: миксины и MRO

Что такое миксин и зачем он нужен?

Миксин — класс без своего состояния (без __init__ и полей), который добавляет методы любому классу-носителю: to_json, аккуратный __repr__, сравнение. Миксины перечисляют первыми в списке родителей, чтобы их методы находились раньше методов базового класса. Так поведение собирается из независимых добавок, без дублирования кода.

Как Python решает алмазную проблему?

Линеаризацией: строится единый порядок MRO, в котором каждый класс встречается один раз, и метод ищется строго по нему — в Child(Left, Right) победит версия из Left. Для инициализации используется кооперативный super(): каждый __init__ передаёт ход следующему классу MRO, поэтому родительский конструктор не вызывается дважды.

Чем super() отличается от вызова родителя по имени?

super() — это «следующий класс в MRO», а не конкретный родитель: в иерархии Child(Left, Right) вызов super() из Left ведёт в Right. Прямой вызов Base.__init__(self) такое не умеет: он жёстко привязан к одному классу и ломает кооперативную цепочку, из-за чего часть инициализаторов не сработает.

Понравился урок? Сошлитесь на него

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.