1. Основы классов и объектов в Python: определение и создание
Основы классов и объектов в Python: определение и создание
Представьте, что вы проектируете каталог товаров для интернет-магазина. У каждого товара есть название, цена и количество на складе. Если бы вы описывали каждый товар отдельно переменными, вам пришлось бы создавать name_1, price_1, stock_1, затем name_2, price_2, stock_2 — и так для тысяч позиций. Такой подход моментально становится неуправляемым. Именно для решения этой проблемы в программировании существует понятие класса — шаблона, который описывает структуру и поведение однотипных сущностей.
Класс как чертёж
Класс — это абстрактный шаблон, определяющий, какие данные и какие операции доступны для определённого типа объектов. Класс сам по себе не занимает место в памяти под конкретные данные — он лишь описывает устройство. В этом смысле класс похож на чертёж дома: на бумаге указаны размеры комнат, расположение дверей и окон, но сам чертёж — это не дом.
В Python класс объявляется ключевым словом class, за которым следует имя класса и двоеточие. По соглашению имена классов записываются в стиле PascalCase — каждое слово с заглавной буквы без разделителей.
Этот минимальный класс ничего не делает, но уже является валидным. Ключевое слово pass здесь означает «тело пусто» — Python требует, чтобы после двоеточия был хотя бы один оператор.
Конструктор __init__ и атрибуты экземпляра
Чтобы класс стал полезным, ему нужно задать конструктор — специальный метод __init__, который вызывается автоматически при создании нового объекта. В нём определяются атрибуты экземпляра — переменные, уникальные для каждого конкретного объекта.
Параметр self — это ссылка на текущий экземпляр класса. Через self конструктор привязывает переданные значения к конкретному объекту. Значение по умолчанию stock = 0 означает, что если количество не указано, товар считается отсутствующим на складе.
Объект как экземпляр класса
Объект (или экземпляр) — это конкретная реализация класса с заполненными данными. Если класс — чертёж, то объект — это построенный по чертежу дом с реальными стенами и мебелью.
Каждый объект хранит свои собственные значения атрибутов. Обратиться к ним можно через точечную нотацию:
Атрибуты можно изменять после создания объекта — Python не накладывает ограничений на запись, если только вы явно не используете механизмы инкапсуляции, которые будут рассмотрены в следующей статье.
Методы: поведение объектов
Если атрибуты описывают состояние объекта, то методы описывают его поведение. Метод — это функция, определённая внутри класса и принимающая первым параметром self.
Метод is_available возвращает булево значение — есть ли товар в наличии. Метод apply_discount уменьшает цену на заданный процент, а restock пополняет запас. Все три метода работают с атрибутами конкретного экземпляра через self.
Строковое представление: __str__ и __repr__
По умолчанию вывод объекта на экран даёт непонятную информацию вроде <__main__.Product object at 0x7f8b1c>. Чтобы это исправить, определяют специальные методы __str__ и __repr__.
Метод __str__ вызывается при использовании print() и предназначен для человека. Метод __repr__ вызывается в отладочных контекстах и должен однозначно описывать объект — в идеале так, чтобы его можно было воссоздать.
Атрибуты класса против атрибутов экземпляра
Помимо атрибутов, привязанных к конкретному объекту через self, существуют атрибуты класса — они определяются непосредственно в теле класса и общие для всех экземпляров.
Обратиться к атрибуту класса можно как через имя класса, так и через экземпляр:
Однако стоит быть осторожным: если через экземпляр присвоить значение атрибуту с тем же именем, будет создан атрибут экземпляра, который «перекроет» атрибут класса для данного объекта. Остальные экземпляры продолжат видеть исходное значение.
Статические и классовые методы
Иногда методу не нужен доступ ни к конкретному экземпляру, ни к самому классу. Для таких случаев существует декоратор @staticmethod. А @classmethod принимает первым параметром сам класс (cls), а не экземпляр.
Классовый метод from_dict — это фабричный метод: он создаёт экземпляр из словаря, что удобно при работе с данными из JSON или базы данных. Статический метод validate_price проверяет корректность цены, не привязываясь к конкретному объекту.
Встроенные проверки типов
Python — язык с динамической типизацией, поэтому атрибутам можно присваивать значения любого типа. Чтобы контролировать это, используют аннотации типов (как в примерах выше) и библиотеку dataclasses, которая автоматически генерирует __init__, __repr__ и другие методы.
Этот код эквивалентен ручному определению класса с __init__ и __repr__, но значительно компактнее. Аннотации типов не накладывают жёстких ограничений в рантайме, но позволяют статическим анализаторам (например, mypy) находить ошибки до запуска программы.
Классы и объекты — это фундамент, на котором строятся все четыре столпа объектно-ориентированного программирования. Понимание того, как устроены конструкторы, методы и атрибуты, необходимо перед тем, как переходить к контролю доступа к данным внутри объектов.