📖 Теория: повторение уроков 72–74

⚡ Кратко

Множественное наследование объединяет поведение нескольких классов. MRO определяет порядок поиска методов, а super() вызывает следующий класс в этой цепочке. Миксины — это «лёгкие» классы поведения без состояния. Инкапсуляция скрывает детали через публичные, защищённые и приватные атрибуты; @property делает контролируемый доступ удобным.

1. Множественное наследование

Класс может наследовать сразу от нескольких родителей:

class Child(Parent1, Parent2):
    pass
  • Порядок родителей важен — Python ищет методы слева направо.
  • Все методы и атрибуты родителей доступны в дочернем классе.
  • При совпадающих именах выбирается метод первого подходящего родителя.

2. Функция hasattr()

hasattr(obj, name) проверяет, есть ли у объекта атрибут с указанным именем. Часто используется в миксинах, чтобы убедиться, что объект поддерживает нужное поведение.

3. Миксины

Миксин — вспомогательный класс, добавляющий поведение. Обычно он:

  • не имеет собственного состояния (__init__ не определяет);
  • имеет имя, заканчивающееся на Mixin;
  • используется только вместе с другими классами.

4. MRO — порядок разрешения методов

MRO определяет, в каком порядке Python ищет методы при наследовании. Его можно посмотреть:

print(ClassName.__mro__)
print(ClassName.mro())

Правило: обход в глубину слева направо, общий предок проверяется единожды.

5. Функция super()

super() возвращает прокси-объект следующего класса в MRO. В множественном наследовании это позволяет вызвать все реализации метода в цепочке, а не только одну.

6. Композиция и агрегация

АспектКомпозицияАгрегация
СозданиеВнутренний объект создаётся внутри внешнегоПередаётся извне
СвязьЖёсткая («часть-целое»)Слабая («использует»)
Жизненный циклВнутренний объект не живёт без внешнегоМожет существовать отдельно

7. Инкапсуляция

Сокрытие внутреннего устройства объекта и предоставление контролируемого интерфейса.

  • name — публичный атрибут.
  • _name — защищённый (соглашение).
  • __name — приватный (манглируется в _ClassName__name).

8. Декоратор @property

Позволяет управлять доступом к полям через синтаксис атрибутов:

class Temperature:
    def __init__(self, value: float) -> None:
        self.__celsius = value

    @property
    def celsius(self) -> float:
        return self.__celsius

    @celsius.setter
    def celsius(self, value: float) -> None:
        if value < -273.15:
            raise ValueError("Слишком холодно")
        self.__celsius = value

Свойство без сеттера доступно только для чтения.