Наследование
Наследование
Мы умеем создавать классы с атрибутами и методами. Следующий шаг ООП — наследование: создание нового класса на основе существующего. Дочерний класс получает все возможности родителя и может добавить свои или изменить унаследованные.
Зачем нужно наследование
Представьте: есть класс 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.