Keep your place in this quest

Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.

Когда класс наследуется от родительского класса, дочерний класс может иметь свои собственные переменные экземпляра и методы, но иногда ему всё же нужно использовать части кода родителя.

И здесь на помощь приходит функция super().
Она позволяет дочернему классу получить доступ к методам (и косвенно атрибутам) родительского класса — без необходимости жестко прописывать имя родителя.

Одно из самых частых применений super() — вызвать конструктор родителя (__init__) из дочернего класса, чтобы родитель мог настроить свои атрибуты до того, как ребёнок добавит свои.

Когда вы создаёте дочерний класс с собственным методом init, он переопределяет init родителя. Это означает, что при создании объекта дочернего класса будет вызван только init дочернего — конструктор родителя не вызывается автоматически. В итоге любая логика инициализации, значения по умолчанию или атрибуты, определённые в init родителя, будут пропущены, и эти атрибуты останутся неопределёнными в том объекте. Это может привести к неожиданным ошибкам, если родительский класс отвечал за важную инициализацию. Чтобы этого избежать, следует явно вызвать super().init() внутри конструктора дочернего класса — это гарантирует, что инициализация родителя выполнится до добавления или переопределения чего-либо в ребёнке.

Давайте теперь это рассмотрим!


Зачем использовать super().__init__()?

При создании подкласса вы можете добавить новые данные для хранения.
Однако нужно, чтобы атрибуты родителя тоже были правильно инициализированы. Вместо переписывания кода инициализации родителя, просто вызывайте его через super().__init__().

Пример: добавление нового атрибута в подкласс

Допустим, у нас есть класс Animal, который хранит name и age.
Мы хотим сделать подкласс Dog, который дополнительно хранит breed (породу собаки), но при этом хотим пользоваться конструктором Animal для установки name и age.

class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # вызов конструктора Animal
        self.breed = breed           # добавляем атрибут Dog

Как это работает пошагово

  1. При создании объекта Dog вызывается метод __init__ класса Dog.
  2. Внутри Dog.__init__ вызывается super().__init__(name, age), который обращается к Animal.__init__.
  3. Конструктор родителя (Animal.__init__) устанавливает self.name и self.age.
  4. Управление возвращается обратно в Dog.__init__, который устанавливает self.breed.

Таким образом:

  • Атрибуты родителя инициализируются так, как задумано родителем.
  • Дочерний класс может добавлять свои атрибуты, не дублируя код.

Использование класса

dog = Dog("Rex", 4, "Golden Retriever")

print(dog.name)   # Rex
print(dog.age)    # 4
print(dog.breed)  # Golden Retriever

Почему super() лучше, чем прямой вызов родителя по имени

Вы можете вызвать Animal.__init__(self, name, age) напрямую, но использование super() более гибко:

  • Автоматически поддерживает множественное наследование (если класс наследует от нескольких родителей).
  • Упрощает сопровождение кода — если вы переименуете родительский класс, не придётся менять все вызовы.
  • Ясно показывает, что вы намеренно вызываете метод родительского класса.
Совет: всегда вызывайте `super().__init__()` перед установкой собственных атрибутов дочернего класса, чтобы все атрибуты родителя были готовы к использованию.

Итоги

super() — это ваша связь с родительским классом. Используйте его, когда хотите:

  • Повторно использовать код инициализации родителя.
  • Расширять функциональность родителя без дублирования.
  • Сохранять код чистым, удобным для сопровождения и гибким к изменениям в иерархии классов.

В следующем уроке мы изучим приватные методы и переменные — способ защитить внутренние данные класса от доступа и изменения извне.