⚖️ Старый и современный подход

⚡ Различия в двух словах

Старый: явный вызов Parent.__init__(self, ...). Работает, но привязан к имени родителя и плохо масштабируется.

Новый: super().__init__(...) — автоматически находит ближайшего родителя, учитывает иерархию и поддерживает аннотации типов.

Вывод: в современном Python предпочитайте super().

📜 Явный вызов родителя

В исходном материале этот способ показан как работающий, но нежелательный. Он вызывает метод конкретного класса напрямую.

class Employee:
    def __init__(self, name):
        self.name = name


class Programmer(Employee):
    def __init__(self, name, language):
        Employee.__init__(self, name)  # явный вызов родителя
        self.language = language


p = Programmer("Alice", "Python")
print(p.name, p.language)

❌ Почему этот подход плох

  • Жёсткая привязка к имени родительского класса. Если родитель переименуется, придётся менять вызовы во всех наследниках.
  • Не учитывает порядок разрешения методов (MRO). При изменении иерархии или множественном наследовании может вызваться не тот метод.
  • Увеличивает риск забыть передать self вручную.
  • Без аннотаций типов сложнее понять, какие аргументы ожидаются.

✅ Современный вариант с super()

Функция super() сама находит ближайшего родителя согласно MRO. Код становится универсальным и безопасным при изменении иерархии.

class Employee:
    def __init__(self, name: str) -> None:
        self.name = name


class Programmer(Employee):
    def __init__(self, name: str, language: str) -> None:
        super().__init__(name)
        self.language = language


p = Programmer("Alice", "Python")
print(p.name, p.language)

Что улучшилось:

  • Нет жёсткой привязки к имени Employee.
  • Корректно работает при многоуровневом наследовании.
  • Аннотации типов делают интерфейс класса понятным.
  • Меньше ошибок при рефакторинге.

🔗 Порядок разрешения методов

У каждого класса есть атрибут __mro__ (Method Resolution Order), который показывает порядок поиска методов. super() использует именно этот порядок.

class A:
    pass


class B(A):
    pass


class C(B):
    pass


print(C.__mro__)
# (<class 'C'>, <class 'B'>, <class 'A'>, <class 'object'>)
Проверить по документации: подробнее о super() и MRO см. Built-in Functions: super и method resolution order. Аннотации типов выходят за рамки исходного материала.