Объектно-ориентированное программирование (ООП) – это парадигма программирования, в которой для представления данных и для проведения операций над этими данными используются объекты.
Объекты, в свою очередь, являются экземплярами классов – с этой точки зрения классы можно назвать шаблонами для создания объектов определенного типа. Классы определяют:
- структуру данных, которые характеризуют объект;
- свойства (атрибуты) и статус (состояние) объекта;
- операции, которые можно совершать с данными объекта (методы).
В этом примере класс Car (автомобиль) имеет атрибуты make, model, year (марка, модель, год выпуска):
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
Атрибуты – это свойства, характеристики объекта. Они
определяют качества и состояние объекта. Атрибуты объекта перечисляют внутри __init__
метода класса – он вызывается каждый
раз при создании экземпляра класса. Параметр self
создает ссылку на экземпляр класса и позволяет получить доступ к
атрибутам и методам объекта. Для создания экземпляра Car достаточно
вызвать класс, передавая в скобках значения, соответствующие его атрибутам:
my_car = Car("Toyota", "Corolla", 2023)
Теперь, когда атрибутам объекта присвоены значения, можно к ним обращаться – для этого используют выражение название_объекта.атрибут
:
print(f'Марка машины {my_car.make},'
f'\nмодель {my_car.model},'
f'\nгод выпуска - {my_car.year}'
)
Результат:
Марка машины Toyota,
модель Corolla,
год выпуска – 2023
Car – пример простейшего
класса: у него нет ни подклассов, ни методов, кроме обязательного __init__
. Метод – это функция, которая определяет
поведение объекта. Проиллюстрируем создание метода на примере класса WashingMachine
– здесь метод remaining_warranty_time()
определяет срок истечения гарантии на
стиральную машину:
import datetime
class WashingMachine:
def __init__(self, brand, model, purchase_date, warranty_length):
self.brand = brand
self.model = model
self.purchase_date = purchase_date
self.warranty_length = warranty_length
def remaining_warranty_time(self):
today = datetime.date.today()
warranty_end_date = self.purchase_date + datetime.timedelta(days=self.warranty_length)
remaining_time = warranty_end_date - today
if remaining_time.days < 0:
return "Срок действия гарантии истек."
else:
return "Срок действия гарантии истекает через {} дней.".format(remaining_time.days)
# создаем объект стиральной машины
my_washing_machine = WashingMachine("LG", "FH4U2VCN2", datetime.date(2022, 5, 7), 1550)
# вызываем метод для проверки срока истечения гарантии
print(my_washing_machine.remaining_warranty_time())
Результат:
Срок действия гарантии истекает через 1218 дней.
Теперь рассмотрим чуть более сложный пример с подклассами и методами. Предположим, что нам нужно разработать CRM для автосалона. В ПО автосалона должен быть класс Vehicle (транспортное средство), который имеет набор атрибутов:
- марка;
- модель;
- год выпуска;
- стоимость.
Среди методов должна быть операция display_info()
, которая отображает информацию о конкретном транспортном средстве, а помимо классов, в ПО необходимо использовать подклассы.
Подкласс – это класс, который наследует все атрибуты и методы родительского класса (также известного как базовый класс или суперкласс), но при этом может иметь дополнительные, свои собственные, атрибуты и методы. Концепцию наследования мы подробнее разберем ниже.
В ПО для автосалона необходимо создать подкласс Car (легковой автомобиль), который наследует все атрибуты и методы класса Vehicle, и при этом имеет дополнительные атрибуты, например количество дверей и стиль кузова. Аналогично, мы можем создать подкласс Truck (грузовик), который наследует все атрибуты и методы класса Vehicle, и к тому же имеет свои атрибуты – длину кузова и тяговую мощность.
В итоге, взаимодействие классов, подклассов и методов будет выглядеть так:
class Vehicle:
def __init__(self, make, model, year, price):
self.make = make
self.model = model
self.year = year
self.price = price
def display_info(self):
print(f"Марка: {self.make}"
f"\nМодель: {self.model}"
f"\nГод выпуска: {self.year}"
f"\nСтоимость: {self.price} руб")
class Car(Vehicle):
def __init__(self, make, model, year, price, num_doors, body_style):
super().__init__(make, model, year, price)
self.num_doors = num_doors
self.body_style = body_style
class Truck(Vehicle):
def __init__(self, make, model, year, price, bed_length, towing_capacity):
super().__init__(make, model, year, price)
self.bed_length = bed_length
self.towing_capacity = towing_capacity
Создадим экземпляры классов и вызовем метод display_info()
для вывода информации о них:
# создаем объект "легковой автомобиль"
car = Car("Toyota", "Camry", 2022, 2900000, 4, "седан")
# создаем объект "грузовик"
truck = Truck("Ford", "F-MAX", 2023, 6000000, "6162", "13 т")
# выводим информацию о легковом автомобиле и грузовике
car.display_info()
truck.display_info()
Результат:
Марка: Toyota
Модель: Camry
Год выпуска: 2022
Стоимость: 2900000 руб
Марка: Ford
Модель: F-MAX
Год выпуска: 2023
Стоимость: 6000000 руб
В этом примере используется встроенная функция super(), которая позволяет вызывать методы родительского суперкласса из подкласса. Этот прием позволяет переиспользовать методы и расширять их функциональность. В данном случае вызывается метод инициализации super().__init__
, который позволяет применить атрибуты суперкласса к подклассу. При необходимости, помимо унаследованных, можно определить новые свойства, которые относятся только к конкретному подклассу.
Рассмотрим еще один пример – библиотечную программу для хранения информации о книгах и их статусах (есть в наличии, выдана абоненту, получена от абонента и так далее). Здесь класс Book определяет различные характеристики книги – title, author, ISBN, а также задает методы check_out()
и check_in()
, которые выдают / принимают книги, и сообщают о статусах:
class Book:
def __init__(self, title, author, isbn):
self.title = title
self.author = author
self.isbn = isbn
self.checked_out = False
def check_out(self):
if self.checked_out:
print("Книга находится у абонента.")
else:
self.checked_out = True
print("Выдаем книгу абоненту.")
def check_in(self):
if not self.checked_out:
print("Книга в наличии.")
else:
self.checked_out = False
print("Принимаем книгу в библиотеку.")
Создадим объект книги и проверим статусы:
# создаем объект книги
book1 = Book("Война и мир", "Л.Н. Толстой", "978-0743273565")
# выдаем книгу, проверяем статус
book1.check_out()
# проверяем статус повторно
book1.check_out()
# принимаем книгу от читателя
book1.check_in()
# проверяем статус книги повторно
book1.check_in()
Результат:
Выдаем книгу абоненту.
Книга находится у абонента.
Принимаем книгу в библиотеку.
Книга в наличии.
Классы, объекты, атрибуты и методы – самые простые, самые базовые понятия ООП. Эти базовые концепции, в свою очередь, лежат в основе фундаментальных принципов ООП.
Отлично! Вы освоили синтаксис классов и базовые концепции ООП.
Вы умеете создавать классы и объекты, определять атрибуты и методы, и даже познакомились с наследованием. У вас есть все инструменты, чтобы начать писать объектно-ориентированный код.
Но ООП — это не просто синтаксис, это целая философия проектирования. В полной версии урока мы глубоко разберем её первые два фундаментальных принципа:
- Инкапсуляция: Вы научитесь скрывать данные с помощью приватных атрибутов и управлять доступом к ним через геттеры и сеттеры.
- Наследование: Вы глубже поймете, как строить иерархии классов, переопределять и расширять поведение родительских методов.
- 10 практических задач, в которых вы с нуля спроектируете свои собственные классы, применяя эти принципы.
Какие сложности у вас возникают при изучении ООП?