🐍 Самоучитель по Python для начинающих. Часть 18: Основы ООП – инкапсуляция и наследование
Рассмотрим базовые понятия (классы, подклассы и методы) и приступим к изучению первых двух фундаментальных принципов объектно-ориентированного программирования. В конце статьи – 10 заданий, связанных с инкапсуляцией и наследованием.
Объектно-ориентированное программирование (ООП) – это парадигма программирования, в которой для представления
данных и для проведения операций над этими данными используются объекты.
Объекты, в свою очередь, являются экземплярами классов – с
этой точки зрения классы можно назвать шаблонами для создания объектов
определенного типа. Классы определяют:
структуру данных, которые характеризуют объект;
свойства (атрибуты) и статус (состояние) объекта;
операции, которые можно совершать с данными объекта (методы).
В этом примере класс Car (автомобиль) имеет атрибуты make, model, year (марка, модель, год выпуска):
Атрибуты – это свойства, характеристики объекта. Они
определяют качества и состояние объекта. Атрибуты объекта перечисляют внутри__init__ метода класса – он вызывается каждый
раз при создании экземпляра класса. Параметр selfсоздает ссылку на экземпляр класса и позволяет получить доступ к
атрибутам и методам объекта. Для создания экземпляра Car достаточно
вызвать класс, передавая в скобках значения, соответствующие его атрибутам:
Теперь, когда атрибутам объекта присвоены значения, можно к ним обращаться – для этого используют выражение название_объекта.атрибут:
Car– пример простейшего
класса: у него нет ни подклассов, ни методов, кроме обязательного __init__. Метод – это функция, которая определяет
поведение объекта. Проиллюстрируем создание метода на примере класса WashingMachine
– здесь метод remaining_warranty_time() определяет срок истечения гарантии на
стиральную машину:
Теперь рассмотрим чуть более сложный пример с подклассами и методами. Предположим, что нам нужно разработать CRM для автосалона. В ПО автосалона должен быть класс Vehicle (транспортное средство), который имеет набор атрибутов:
марка;
модель;
год выпуска;
стоимость.
Среди методов должна быть операция display_info(), которая отображает информацию о конкретном транспортном средстве, а помимо классов, в ПО необходимо использовать подклассы.
Подкласс – это класс, который наследует все атрибуты и методы родительского класса (также известного как базовый класс или суперкласс), но при этом может иметь дополнительные, свои собственные, атрибуты и методы. Концепцию наследования мы подробнее разберем ниже.
В ПО для автосалона необходимо создать подкласс Car (легковой автомобиль), который наследует все атрибуты и методы класса Vehicle, и при этом имеет дополнительные атрибуты, например количество дверей и стиль кузова. Аналогично, мы можем создать подкласс Truck (грузовик), который наследует все атрибуты и методы класса Vehicle, и к тому же имеет свои атрибуты – длину кузова и тяговую мощность.
В итоге, взаимодействие классов, подклассов и методов будет выглядеть так:
Создадим экземпляры классов и вызовем метод display_info() для вывода информации о них:
Результат:
В этом примере используется встроенная функция super(), которая позволяет вызывать методы родительского суперкласса из подкласса. Этот прием позволяет переиспользовать методы и расширять их функциональность. В данном случае вызывается метод инициализации super().__init__, который позволяет применить атрибуты суперкласса к подклассу. При необходимости, помимо унаследованных, можно определить новые свойства, которые относятся только к конкретному подклассу.
Рассмотрим еще один пример – библиотечную программу для хранения информации о книгах и их статусах (есть в наличии, выдана абоненту, получена от абонента и так далее). Здесь класс Book определяет различные характеристики книги – title, author, ISBN, а также задает методы check_out() и check_in(), которые выдают / принимают книги, и сообщают о статусах:
Создадим объект книги и проверим статусы:
Результат:
Классы, объекты, атрибуты и методы – самые простые, самые
базовые понятия ООП. Эти базовые концепции, в свою очередь, лежат в основе
фундаментальных принципов ООП.
ООП основывается на четырех фундаментальных принципах:
инкапсуляции, наследовании, полиморфизме и абстракции.
Инкапсуляция – механизм сокрытия деталей реализации класса
от других объектов. Достигается путем использования модификаторов доступа public,
private и protected, которые соответствуют публичным, приватным и защищенным
атрибутам.
Наследование – процесс создания нового класса на основе
существующего класса. Новый класс, называемый подклассом или производным
классом, наследует свойства и методы существующего класса, называемого
суперклассом или базовым классом.
Полиморфизм – способность объектов принимать различные
формы. В ООП полиморфизм позволяет рассматривать объекты разных классов так,
как если бы они были объектами одного класса.
Абстракция – процесс определения существенных характеристик
объекта и игнорирования несущественных характеристик. Это позволяет создавать
абстрактные классы, которые определяют общие свойства и поведение группы
объектов, не уточняя детали каждого объекта.
В этой статье мы рассмотрим на конкретных примерах первые
две концепции, а в следующей – остальные.
Инкапсуляция
Сделаем атрибуты title, author и isbnкласса Bookприватными – теперь доступ к ним возможен только внутри
класса:
Чтобы получить доступ к этим атрибутам извне класса, мы определяем методы getter и setter, которые обеспечивают контролируемый доступ к атрибутам:
В этом примере методы get_title(), get_author() и get_isbn() являются получающими
методами (геттерами), которые позволяют нам получать значения приватных атрибутов
извне класса. Методы set_title(), set_author() и set_isbn() – устанавливающиеметоды (сеттеры), которые позволяют нам
устанавливать значения частных атрибутов извне класса.
Создадим экземпляр объекта и попытаемся получить доступ к
его названию с помощью обычного метода:
Результат – ошибка:
Воспользуемся геттерами:
Результат:
Изменим название с помощью сеттера и выведем результат:
Результат:
Наследование
Для иллюстрации концепции наследования мы определим класс Publication, который
имеет свойства, общие для всех публикаций – title, author и year, а также общий
метод display():
Теперь создадим два подкласса Book и Magazine, которые
наследуют все свойства и методы от класса Publication, и кроме того, имеют свои
атрибуты. Подкласс Book добавляет свойство isbn и переопределяет метод
display() для включения свойства isbn. Подкласс Magazine добавляет свойство issue_number
(номер выпуска) и переопределяет метод display() для включения свойства issue_number:
Теперь, если мы создадим экземпляр класса Book или класса Magazine, мы сможем вызвать метод display() для отображения свойств объекта. Сначала будет вызван метод display() подкласса (Book или Magazine), который в свою очередь вызовет метод display() суперкласса Publication с помощью функции super(). Это позволяет нам повторно использовать код суперкласса и избежать дублирования кода в подклассах:
Результат:
Практика
Задание 1
Напишите класс MusicAlbum, у которого есть:
Атрибуты title, artist, release_year, genre, tracklist (название, исполнитель, год выхода, жанр, список треков.
Метод play_random_track() для вывода случайного названия песни.
метод average_score – для вычисления среднего балла успеваемости.
Пример использования:
Вывод:
Решение:
Задание 3
Напишите класс Recipe с двумя методами:
print_ingredients(self) – выводит список продуктов, необходимых для приготовления блюда;
cook(self) – сообщает название выбранного рецепта и уведомляет о готовности блюда.
Пример использования:
Вывод:
Решение:
Задание 4
Напишите суперкласс Publisher(издательство) и два подкласса BookPublisher (книжное издательство) и NewspaperPublisher(газетное
издательство).
Родительский класс Publisher имеет два атрибута name и location (название, расположение) и два метода:
get_info(self) – предоставляет информацию о названии и расположении издательства;
publish(self, message) – выводит информацию об издании, которое находится в печати.
Подклассы BookPublisher
и NewspaperPublisherиспользуют метод super().__init__(name, location) суперкласса для вывода информации о своих названии и
расположении, и кроме того, имеют собственные атрибуты:
BookPublisher – num_authors (количество авторов).
NewspaperPublisher– num_pages (количество страниц в газете).
Пример использования:
Вывод:
Решение:
Задание 5
Создайте класс BankAccount, который имеет следующие свойства:
balance – приватный атрибут для хранения текущего баланса счета;
interest_rate –приватный атрибут для процентной ставки;
transactions – приватный атрибут для списка всех операций, совершенных по счету.
Класс BankAccount должен иметь следующие методы:
deposit(amount) – добавляет сумму к балансу и регистрирует транзакцию;
withdraw(amount) – вычитает сумму из баланса и записывает транзакцию;
add_interest() – добавляет проценты к счету на основе interest_rate и записывает транзакцию;
history() – печатает список всех операций по счету.
Пример использования:
Вывод:
Решение:
Задание 6
Создайте класс Employee (сотрудник), который имеет следующие
приватные свойства:
name – имя сотрудника;
age – возраст;
salary – оклад;
bonus – премия.
Класс Employee должен иметь следующие методы:
get_name() – возвращает имя сотрудника;
get_age() – возвращает возраст;
get_salary() – возвращает зарплату сотрудника;
set_bonus(bonus) – устанавливает свойство bonus;
get_bonus() – возвращает бонус для сотрудника;
get_total_salary() – возвращает общую зарплату сотрудника (оклад + бонус).
Пример использования:
Вывод:
Решение:
Задание 7
Напишите
класс Animal, обладающий свойствамиname, species, legs, в которых хранятся данные о кличке, виде и количестве ног животного.
Класс также должен иметь два метода – voice() и move(), которые
сообщают о том, что животное подает голос и двигается.
Создайте два подкласса –Dog и Bird. Подкласс Dog имеет атрибут breed (порода) и метод bark(), который сообщает о том, что собака лает. Подкласс Bird обладает свойством wingspan
(размах крыльев) и методом fly(), который уведомляет о полете птицы.
Пример использования:
Вывод:
Решение:
Задание 8
Создайте класс Shape(геометрическая фигура)со свойствами nameи color (название и цвет). У
этого класса должны быть три подкласса – Circle (окружность), Rectangle (прямоугольник),
и Triangle (треугольник). Каждый подкласс наследует атрибут color и методdescribe() родительского класса Shape, и при этом имеет дополнительные
свойства и методы:
Circle – атрибут radius и метод area() для вычисления площади.
Rectangle – атрибуты length и width, свой метод area().
Triangle – атрибуты base и height (основание и высота), собственный метод area().
Пример использования:
Вывод:
Решение:
Задание 9
Для ПО кондитерской фабрики нужно написать родительский класс
Candy (Конфеты). Этот
класс имеет атрибуты name, price, weight (наименование, цена, вес). Подклассы Chocolate, Gummy, HardCandy (шоколад, жевательный
мармелад, леденец) наследуют все атрибуты суперкласса Candy. Кроме того, у них есть и свои
атрибуты:
Chocolate – cocoa_percentage (процент содержания какао) и chocolate_type (сорт шоколада).
Gummy – flavor и shape (вкус и форма).
HardCandy – flavor и filled (вкус и начинка).
Пример использования:
Вывод:
Решение:
Задание 10
Для военной игры-стратегии нужно
написать класс Soldier
(солдат). Класс имеет атрибуты name, rank и service_number (имя, воинское
звание, порядковый номер), причем звание и номер – приватные свойства.
Напишите методы для:
получения воинского звания;
подтверждения порядкового номера;
повышения в звании;
понижения в звании.
Кроме того, нужно создать
декоратор для вывода информации о персонаже.
Пример использования:
Вывод:
Решение:
Подведем итоги
Мы рассмотрели базовые понятия ООП – классы, объекты,
методы, и научились решать задачи, связанные с инкапсуляцией и наследованием. В
следующей статье будем изучать остальные фундаментальные принципы ООП –
полиморфизм и абстракцию.