Наследование

Наследование

Мы умеем создавать классы с атрибутами и методами. Следующий шаг ООП — наследование: создание нового класса на основе существующего. Дочерний класс получает все возможности родителя и может добавить свои или изменить унаследованные.

Зачем нужно наследование

Представьте: есть класс Animal с базовыми характеристиками (имя, возраст, звук). Собака, кошка, птица — все животные, но ведут себя по-разному. Без наследования пришлось бы копировать одинаковый код в каждый класс. С наследованием: один раз написать в Animal, переопределить только отличия.

Синтаксис наследования

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

    def speak(self):
        return "..."

    def describe(self):
        return f"{self.name}, {self.age} лет"

class Dog(Animal):   # Dog наследует от Animal
    def speak(self):   # переопределяем метод
        return "Гав!"

class Cat(Animal):
    def speak(self):
        return "Мяу!"

buddy = Dog("Buddy", 3)
whiskers = Cat("Whiskers", 5)

print(buddy.describe())   # Buddy, 3 лет — унаследовано от Animal
print(buddy.speak())      # Гав! — переопределено в Dog
print(whiskers.speak())   # Мяу!

Animal — родительский класс (базовый, суперкласс). Dog и Cat — дочерние (производные, подклассы).

super() — вызов метода родителя

Когда дочерний класс переопределяет __init__, он должен вызвать инициализатор родителя через super(), чтобы не потерять логику из родительского класса:

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)   # вызываем __init__ Animal
        self.breed = breed             # добавляем свой атрибут

    def speak(self):
        return f"Гав! Я {self.breed}"

buddy = Dog("Buddy", 3, "Лабрадор")
print(buddy.describe())   # Buddy, 3 лет
print(buddy.speak())      # Гав! Я Лабрадор

super() возвращает объект родительского класса. Так Dog.__init__ вызывает Animal.__init__, не дублируя код.

isinstance и issubclass

print(isinstance(buddy, Dog))     # True
print(isinstance(buddy, Animal))  # True — Dog IS-A Animal
print(isinstance(buddy, Cat))     # False

print(issubclass(Dog, Animal))    # True
print(issubclass(Cat, Dog))       # False

isinstance проверяет принадлежность объекта к классу или его потомкам — это полезнее, чем type(obj) == Dog.

Переопределение и расширение методов

Дочерний класс может полностью заменить метод или расширить его через super():

class Animal:
    def describe(self):
        return f"{self.name}, {self.age} лет"

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

    def describe(self):
        base = super().describe()   # получаем базовое описание
        return f"{base}, порода: {self.breed}"

buddy = Dog("Buddy", 3, "Лабрадор")
print(buddy.describe())
# Buddy, 3 лет, порода: Лабрадор

Проверь себя

Что выведет следующий код?

class Shape:
    def area(self):
        return 0

class Square(Shape):
    def __init__(self, side):
        self.side = side

    def area(self):
        return self.side ** 2

s = Square(4)
print(isinstance(s, Shape))
print(s.area())

isinstance(s, Shape)True (Square — потомок Shape). s.area()16 (переопределённый метод).

Итог

  • class Child(Parent): — дочерний класс наследует все атрибуты и методы родителя.
  • Дочерний класс может переопределить любой метод родителя.
  • super().__init__(...) — вызов инициализатора родителя; обязателен при переопределении __init__.
  • isinstance(obj, ClassName) — проверка принадлежности к классу и его потомкам.
  • Наследование устраняет дублирование: общий код — в родителе, специфика — в потомках.

В следующем уроке разберём магические методы (__str__, __repr__, __eq__) — они позволяют объектам работать со встроенными операциями Python.

Попробуйте интерактивную версию

Практические задачи, квизы и AI-наставник — бесплатный старт без карты

Перейти к практике