Класс оборачивает данные и то, что ты с ними делаешь
Класс позволяет определить тип сущности — пользователя, банковский счёт, конфигурацию, запрос — и всё, что эта сущность умеет. Сама сущность — экземпляр класса. Действия называются методами.
Простейший возможный класс:
Разбираем:
class User:открывает определение класса. Имена классов по соглашению в PascalCase.__init__— инициализатор. Он вызывается автоматически при создании нового экземпляра и задаёт атрибуты черезself.whatever = ....greet— метод.self— то, через что метод обращается к экземпляру, на котором его позвали.User("Rosa", "rosa@example.com")создаёт экземпляр. Python вызывает__init__сself, равным новому экземпляру, и остальными аргументами.user.greet()вызывает метод. Python передаётuserкакselfавтоматически.
self — просто первый аргумент
self — не ключевое слово. Это имя, которое Python даёт первому параметру методов экземпляра, — самого экземпляра, на котором метод работает. Формально можно назвать как угодно; все используют self, потому что все используют self.
Каждый метод экземпляра берёт self первым параметром. Так метод знает, из какого экземпляра читать и что менять.
Добавляем поведение
Методы умеют читать и изменять состояние:
__repr__ — ещё один специальный метод, хук «как мне показаться при печати». Хорошая реализация окупается во время отладки.
Атрибуты класса vs атрибуты экземпляра
Атрибуты, определённые в теле класса (вне __init__), делятся между всеми экземплярами. Атрибуты, присваиваемые self, — у каждого свои:
Используй атрибуты класса для по-настоящему общих значений — констант, счётчиков, конфигов. Всё, что специфично экземпляру, — в __init__.
Наследование
Класс может наследовать другой, получая его методы и атрибуты даром, и добавлять или переопределять по нужде:
super() даёт доступ к родителю — часто используется внутри __init__, чтобы инициализировать родительские атрибуты перед добавлением своих:
Наследование полезно, но легко пере-использовать. Начинающий питонист часто тянется к нему, когда композиция — держать объект как атрибут — понятнее. Начинай с плоской структуры классов и вводи наследование только при настоящем отношении «is-a».
Dataclasses: более приятный дефолт для записей
Когда класс в основном нужен для пары атрибутов с нормальным равенством и репрезентацией, @dataclass избавляет от бойлерплейта:
Сравни с ручной записью __init__, __repr__ и __eq__. Dataclass — правильный первый выбор, когда иначе ты написал бы class Thing только с __init__, проставляющим атрибуты.
Property: вычисляемые атрибуты
Иногда хочется «атрибут», который на самом деле вычисляется. @property делает это похожим на обращение к атрибуту:
Используй property, когда ты написал бы obj.get_something(), — замена на property делает API естественнее. Не прячь за ним дорогие операции: пользователь ожидает, что обращение к атрибуту — быстрое.
Приватное по соглашению
В Python нет настоящей приватности. По соглашению атрибуты с ведущим подчёркиванием предполагаются приватными — читатель не должен трогать их снаружи класса:
class Cache:
def __init__(self):
self._store = {}
def put(self, key, value):
self._store[key] = value
def get(self, key, default=None):
return self._store.get(key, default)
Имена с двойным подчёркиванием (__name) включают name mangling: к атрибуту добавляется имя класса. Это инструмент против коллизий при наследовании, а не защита.
Когда класс не нужен
Если у тебя просто набор связанных данных — сойдёт dataclass, обычный словарь или namedtuple. Если у тебя одна функция — ей не нужен класс-обёртка. Тянись к классам, когда у тебя и состояние, и поведение связаны вместе — особенно если будет много экземпляров одного рода.
Финальный пример
Маленький файло-подобный лог-буфер:
Обрати внимание на __len__ — ещё один магический метод. Его определение делает len(logger) работающим, потому что len(x) — это на самом деле вызов x.__len__(). В Python десятки таких хуков; подбирай по мере надобности.
Дальше: генераторы
Классы связывают данные и поведение. Следующая глава смотрит на другой вид абстракции — итерацию — начиная с генераторов: функций, которые выдают значения по одному, делая паузы между ними. Они прекрасно сочетаются с оператором with и контекстными менеджерами, которые встретим сразу после.
Часто задаваемые вопросы
Что такое класс в Python?
Класс — это чертёж для создания объектов, собирающих данные (атрибуты) и поведение (методы) вместе. class User: определяет класс User; User(...) создаёт экземпляр. Классы — главный инструмент Python для моделирования вещей, у которых есть и состояние, и поведение.
Что значит self в Python?
self — первый параметр каждого метода экземпляра. Когда ты вызываешь user.greet(), Python передаёт экземпляр user как self. Внутри метода self.name обращается к атрибуту этого пользователя. Имя self — соглашение, не ключевое слово, но его использует каждый питонист.
Python — объектно-ориентированный язык?
Да — всё в Python объекты, включая числа, строки и функции. ООП можно делать, когда это уместно, но Python не навязывает его. Многие реальные Python-программы используют классы скупо, предпочитая обычные функции и структуры данных там, где это возможно.