В предыдущем уроке мы изучили основы объектно-ориентированного программирования: классы, объекты, атрибуты, методы, свойства, статические методы и методы класса. Это фундамент, на котором строится ООП. Но настоящая мощь ООП раскрывается с помощью наследования и полиморфизма — механизмов, позволяющих создавать иерархии классов, переиспользовать код и создавать гибкие, расширяемые программы.
Представьте, что вы пишете программу для зоопарка. У вас есть животные разных видов: львы, слоны, пингвины, змеи. У всех животных есть общие характеристики: имя, возраст, вес. И общее поведение: они едят, спят, издают звуки. Но у каждого вида есть и свои особенности: львы рычат, слоны трубят, пингвины умеют плавать, а змеи ползать. Вместо того чтобы создавать отдельные классы для каждого вида с нуля (и дублировать общие атрибуты и методы), мы можем создать один общий класс Animal (базовый класс), а затем создать классы-наследники Lion, Elephant, Penguin, Snake, которые унаследуют всё общее от Animal и добавят свои уникальные особенности. Это и есть наследование.
В этом уроке мы подробно изучим наследование и полиморфизм в Python. Вы узнаете, что такое базовый (родительский) класс и производный (дочерний) класс, как создать дочерний класс от родительского, и как дочерний класс автоматически получает все атрибуты и методы родительского. Научимся переопределять методы родительского класса в дочернем — например, метод make_sound() в классе Animal может быть общим, а в классе Lion мы переопределим его, чтобы он выводил «Рррр!».
Особое внимание уделим функции super() — специальной функции, которая позволяет вызывать методы родительского класса из дочернего. Это необходимо, когда мы переопределяем метод __init__ в дочернем классе, но при этом хотим сохранить инициализацию атрибутов, унаследованных от родителя. Разберём, как работает super() и почему без него легко допустить ошибку при множественном наследовании.
Изучим множественное наследование — возможность создавать класс, который наследуется от нескольких родительских классов. Python поддерживает множественное наследование, но с ним нужно быть осторожным из-за проблемы «ромбовидного наследования». Вы узнаете о порядке разрешения методов (MRO — Method Resolution Order), который определяет, в каком порядке Python ищет методы в иерархии наследования, и как посмотреть MRO с помощью атрибута __mro__ и метода mro().
Познакомимся с инкапсуляцией — механизмом, скрывающим внутренние детали реализации. В Python нет строгой инкапсуляции, но есть соглашения: одно подчёркивание _name означает «защищённый» (не трогай снаружи), а два подчёркивания __name запускают механизм name mangling (искажение имени), который делает атрибут более приватным.
Научимся создавать абстрактные классы с помощью модуля abc (Abstract Base Classes). Абстрактный класс — это класс, который не предназначен для создания объектов. Он служит шаблоном для других классов и может содержать абстрактные методы — методы, которые объявлены, но не реализованы. Дочерние классы обязаны реализовать эти абстрактные методы. Это полезно для определения интерфейсов и гарантии того, что все классы-наследники будут иметь определённые методы.
Все примеры будут максимально практичными: создадим иерархию классов Animal → Lion/Elephant/Penguin, систему оплаты Payment → CreditCardPayment/PayPalPayment/CryptoPayment, геометрические фигуры Shape → Rectangle/Circle/Triangle. К концу урока вы будете уверенно использовать наследование и полиморфизм для создания гибких и расширяемых программ.