1. Основы ООП: создание классов, работа с атрибутами и методы экземпляра
Основы ООП: создание классов, работа с атрибутами и методы экземпляра
Добро пожаловать в курс «Классы в Python и углубленное изучение декораторов». Мы начинаем наше путешествие с фундаментальной темы, которая лежит в основе большинства современных программных систем — Объектно-Ориентированного Программирования (ООП).
Прежде чем мы доберемся до магии декораторов и метаклассов, нам нужно построить прочный фундамент. Сегодня мы разберем, что такое классы, чем они отличаются от объектов, как хранить данные внутри объектов и как заставить их совершать действия.
Что такое ООП и зачем оно нужно?
Представьте, что вы пишете программу для управления автопарком. Если использовать только функции и переменные (процедурный стиль), вам придется создавать множество списков или словарей для хранения данных о каждой машине: марка, модель, год выпуска, пробег. Затем вам понадобятся отдельные функции, которые принимают эти данные и что-то с ними делают.
С ростом программы код превратится в запутанный клубок данных и функций. ООП предлагает другое решение: объединить данные (характеристики) и функции (действия) в единую сущность.
Аналогия с чертежом и домом
Чтобы понять разницу между классом и объектом (экземпляром), давайте используем классическую аналогию.
* Класс — это чертеж, шаблон или инструкция. Он описывает, какими свойствами должен обладать объект и что он должен уметь делать. Сам по себе класс не содержит конкретных данных (например, конкретного пробега). * Объект (или экземпляр класса) — это конкретная реализация этого чертежа. У него есть свои уникальные значения свойств.
В Python всё является объектом: строки, числа, списки. Когда вы создаете строку s = "Привет", вы создаете объект класса str.
Создание первого класса
В Python создание класса начинается с ключевого слова class. По общепринятому соглашению (PEP 8), имена классов пишутся в стиле CapWords (каждое слово с большой буквы, без подчеркиваний).
Здесь мы создали простейший класс Car. Оператор pass используется как заглушка, так как тело класса не может быть пустым.
Теперь мы можем создать экземпляры (объекты) этого класса:
Результат будет примерно таким:
<__main__.Car object at 0x7f...>
<__main__.Car object at 0x7f...>
Мы видим, что это два разных объекта, находящихся в разных ячейках памяти.
Атрибуты: наделяем объекты данными
Пустые объекты бесполезны. Нам нужно, чтобы у каждой машины были свои характеристики: цвет, марка, скорость. В терминологии ООП переменные, принадлежащие объекту, называются атрибутами.
Мы могли бы добавлять атрибуты вручную после создания объекта:
Но это плохой подход. Он не гарантирует, что у всех машин будут одинаковые наборы характеристик. Правильный способ — инициализировать атрибуты при создании объекта.
Магический метод __init__
Для начальной настройки объекта в Python используется специальный метод __init__. Его часто называют конструктором (хотя технически это инициализатор).
Этот метод запускается автоматически в момент создания нового экземпляра класса.
Давайте разберем этот код детально.
def __init__: Имя метода строго фиксировано. Двойные подчеркивания с обеих сторон указывают на то, что это «магический» метод Python.(self, brand, color): В скобках мы указываем параметры, которые нужно передать при создании объекта.self.brand = brand: Это самая важная часть. Мы берем значение аргумента brand и сохраняем его внутри объекта в атрибут с именем brand.Теперь создание машин выглядит так:
Загадочный self
Вы наверняка заметили слово self, которое стоит первым аргументом в методе __init__ и используется внутри него. Это часто сбивает с толку новичков.
self — это ссылка на конкретный объект, с которым мы сейчас работаем.
Когда вы пишете toyota = Car("Toyota", "White"), Python под капотом делает примерно следующее:
__init__, передавая этот новый пустой объект в качестве первого аргумента — self.То есть:
* Внутри объекта toyota переменная self ссылается на toyota.
* Внутри объекта bmw переменная self ссылается на bmw.
Благодаря self код класса знает, какому именно объекту нужно присвоить цвет «White», а какому — «Black».
> Важно: Имя self — это просто соглашение. Вы могли бы назвать этот аргумент this или me, и код бы работал. Однако использование любого другого имени, кроме self, считается грубым нарушением этикета Python-разработчика.
Методы экземпляра: учим объекты действовать
Атрибуты описывают состояние объекта. Методы описывают его поведение. Технически, методы — это функции, объявленные внутри класса.
Главное отличие метода от обычной функции заключается в том, что метод всегда (за редким исключением, о котором мы поговорим в будущих статьях) принимает self первым аргументом.
Добавим нашей машине возможность разгоняться и тормозить.
Вызов методов
Обратите внимание: при объявлении метода мы пишем def accelerate(self, value), но при вызове мы не передаем self вручную.
Вывод:
Если вы забудете указать self в определении метода (def accelerate(value):), то при попытке вызова my_car.accelerate(20) получите ошибку TypeError. Python попытается передать объект my_car первым аргументом, но функция его не ждет.
Взаимодействие объектов
Сила ООП раскрывается, когда объекты начинают взаимодействовать друг с другом. Давайте создадим класс Driver (Водитель) и научим его взаимодействовать с Car.
Здесь метод drive принимает не просто число или строку, а целый объект машины (car).
Результат:
В этом примере объект driver использует публичные методы и атрибуты объекта my_car, чтобы изменить его состояние. Это демонстрирует, как сложные системы строятся из простых, взаимодействующих блоков.
Инкапсуляция (краткое введение)
В наших примерах мы свободно обращались к атрибутам car.speed или car.brand напрямую. В серьезном программировании часто требуется защитить данные от некорректного изменения извне (например, чтобы нельзя было установить отрицательную скорость).
Хотя Python не имеет строгого запрета на доступ к данным (как private в Java или C++), существует соглашение: если имя атрибута начинается с нижнего подчеркивания (например, _engine_status), это сигнал для программиста: «Не трогай это снаружи класса, это для внутреннего использования».
Более подробно о защите данных и свойствах (property) мы поговорим в следующих статьях курса.
Резюме
Сегодня мы заложили первый камень в фундамент вашего понимания ООП в Python.
__init__.self — это ссылка на текущий объект, позволяющая методам работать с данными именно этого экземпляра.В следующей статье мы углубимся в работу с атрибутами класса, статическими методами и начнем подбираться к теме наследования.