Наследование: расширяем классы
Наследование — способ расширять классы без переписывания: потомок получает всё от родителя, переопределяет и дополняет через super(). Родство проверяет isinstance.
Редакция Питоники
Классы из первых уроков живут поодиночке, но реальные сущности образуют семьи: собака — это животное, щенок — это собака; товар и его скидочная версия; пользователь и администратор. Наследование позволяет описать общее один раз в родителе, а в потомках — только отличия: это фундамент полиморфизма, о котором — через два урока. Синтаксис прост: class Dog(Animal) — «собака есть животное».
Родитель и потомок: Animal и Dog
Класс в скобках — родитель (базовый класс), новый — потомок (подкласс). Потомок получает всё: атрибуты и методы родителя работают, как будто вы написали их заново. Поверх унаследованного потомок добавляет своё.
class Animal:
def __init__(self, name):
self.name = name
def sleep(self):
print(f"{self.name} спит")
class Dog(Animal):
def bark(self):
print(f"{self.name} говорит: Гав!")
rex = Dog("Рекс")
rex.sleep()
rex.bark()
Рекс спит Рекс говорит: Гав!
Переопределение и super()
class Animal:
def __init__(self, name):
self.name = name
def voice(self):
print(f"{self.name} издаёт звук")
class Cat(Animal):
def voice(self):
print(f"{self.name} говорит: Мяу")
class Cow(Animal):
def voice(self):
print(f"{self.name} говорит: Муу")
zoo = [Cat("Барсик"), Cow("Зорька"), Animal("Существо")]
for animal in zoo:
animal.voice()
Барсик говорит: Мяу Зорька говорит: Муу Существо издаёт звук
class Animal:
def __init__(self, name):
self.name = name
def voice(self):
print(f"{self.name} издаёт звук")
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name)
self.breed = breed
def voice(self):
super().voice()
print("Гав-гав!")
class Puppy(Dog):
def voice(self):
super().voice()
print("Тяв-тяв!")
puppy = Puppy("Бублик", "мопс")
puppy.voice()
print(puppy.name, puppy.breed)
Бублик издаёт звук Гав-гав! Тяв-тяв! Бублик мопс
super() означает «возьми ближайшую родительскую реализацию по цепочке наследования и продолжи с ней». В цепочке Animal — Dog — Puppy вызов super().voice() в щенке находит voice у собаки, а собачий super() — голос животного: поведение складывается этажами. Куда именно смотрит super() в сложных иерархиях — тема урока про MRO. А проверить родственные связи помогает isinstance — он отвечает True и для класса самого объекта, и для всех его родителей.
| Проверка | Результат | Что проверяет |
|---|---|---|
| isinstance(rex, Puppy) | True | точный класс объекта |
| isinstance(rex, Dog) | True | класс-родитель в цепочке |
| isinstance(rex, Animal) | True | вся цепочка наследования |
| issubclass(Puppy, Dog) | True | наследование классов без экземпляра |
class Animal:
pass
class Dog(Animal):
pass
class Puppy(Dog):
pass
rex = Puppy()
print(isinstance(rex, Puppy))
print(isinstance(rex, Dog))
print(isinstance(rex, Animal))
print(isinstance(rex, int))
True True True False
Сначала предскажи ответ в голове — это главный навык программиста.
class Animal:
def __init__(self, name):
self.name = name
def voice(self):
print("...")
class Dog(Animal):
def voice(self):
print("Гав!")
dog = Dog("Рекс")
dog.voice()
class Animal:
def __init__(self, name):
self.name = name
class Cat(Animal):
def __init__(self, name, whiskers):
super().__init__(name)
self.whiskers = whiskers
cat = Cat("Барсик", 24)
print(cat.name, cat.whiskers)
class A:
def hello(self):
print("A")
class B(A):
def hello(self):
print("B")
class C(B):
pass
obj = C()
obj.hello()
1. Что даёт запись class Dog(Animal)?
2. Что значит переопределить метод?
3. Зачем в __init__ потомка вызывают super().__init__(name)?
4. isinstance(rex, Animal) при цепочке Animal — Dog — Puppy вернёт...
5. Сработает ли rex.sleep(), если sleep определён только в Animal?
6. Что делает super().voice() внутри Puppy.voice?
Постройте цепочку Vehicle — Car. Vehicle хранит число колёс в __init__(self, wheels) и умеет describe(): печатает «Транспорт, колёс: N». Car наследует Vehicle: его __init__(self, model, wheels) вызывает super().__init__(wheels) и сохраняет model; describe() у Car сначала вызывает super().describe(), затем печатает «Автомобиль: модель». Создайте Car("Жигули", 4) и вызовите describe().
Что такое наследование в Python простыми словами?
Это связь «является»: class Dog(Animal) означает «собака является животным». Потомок автоматически получает все атрибуты и методы родителя, добавляет свои и при необходимости переопределяет унаследованные. Общее поведение описывается один раз — в родителе.
Что делает super()?
Даёт доступ к реализации родителя из метода потомка. Чаще всего вызывается в __init__ потомка — super().__init__(...) настраивает родительскую часть объекта — и в переопределённых методах, когда нужно дополнить поведение, а не заменить его.
Чем переопределение отличается от расширения метода?
Переопределение (тот же def voice в потомке) заменяет родительскую версию полностью. Расширение — это переопределение с вызовом super().voice() внутри: сначала отрабатывает родитель, потом добавляется своё. Для сценария «сделай как родитель, плюс» выбирайте второе.
Урок 8: super() и MROКак проверить, что объект принадлежит классу или его потомкам?
Функцией isinstance(obj, Class): она вернёт True и для точного класса, и для любого родителя в цепочке — isinstance(rex, Animal) истинно для щенка. Наследование между классами без экземпляров проверяет issubclass(Puppy, Dog), а точный класс — type(rex) is Puppy.
Понравился урок? Сошлитесь на него
«super() означает «возьми ближайшую родительскую реализацию по цепочке наследования и продолжи с ней».»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что читать дальше
ООП · Урок 5
Инкапсуляция: _protected и __private
Одно подчёркивание — договорённость, два — искажение имени. Учимся прятать детали класса за публичным интерфейсом и понимать name mangling.
ООП · Урок 6
@property: вычисляемые атрибуты
@property превращает метод в атрибут без скобок: площадь пересчитывается сама, сеттер проверяет данные. Разбираем, когда свойство излишне.
ООП · Урок 8
super() и порядок MRO: как Python ищет методы
super() вызывает не «метод родителя», а следующий метод в порядке MRO — порядке, в котором Python ищет атрибуты по иерархии. Разбираем __mro__, расширение методов и кооперативные цепочки вызовов.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
pytest · Урок 16
Тестирование классов: методы, состояние и Test-классы
Корзина магазина как подопытная: фикстура раздаёт каждому тесту свежий объект, Test-класс наводит порядок в методах — и ни одно состояние не протекает.
pytest тестирование классовpytest Test класс
Flask · Урок 3
Шаблоны Jinja2: HTML-страницы с данными из Python
Третий урок курса Flask: шаблоны Jinja2 — переменные, циклы, фильтры и наследование base.html. Отличие этого урока: все примеры Jinja2 можно отрендерить прямо на странице.
наследование шаблонов jinja2
ООП · Урок 1
Классы в Python: первый объект
Класс — чертёж, объект — экземпляр по этому чертежу. Создаём первый класс, вызываем методы и убеждаемся: в Python объектом является всё, включая функции.
классы pythonpython классы