Menu
Русский

Классы в Python: __init__, self, методы, наследование и dataclasses

Введение в классы Python для начинающих — определение, создание экземпляров, метод __init__, наследование и когда вместо обычного класса брать dataclass.

Класс оборачивает данные и то, что ты с ними делаешь

Класс позволяет определить тип сущности — пользователя, банковский счёт, конфигурацию, запрос — и всё, что эта сущность умеет. Сама сущностьэкземпляр класса. Действия называются методами.

Простейший возможный класс:

main.py
Output
Click Run to see the output here.

Разбираем:

  • 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 первым параметром. Так метод знает, из какого экземпляра читать и что менять.

Добавляем поведение

Методы умеют читать и изменять состояние:

main.py
Output
Click Run to see the output here.

__repr__ — ещё один специальный метод, хук «как мне показаться при печати». Хорошая реализация окупается во время отладки.

Атрибуты класса vs атрибуты экземпляра

Атрибуты, определённые в теле класса (вне __init__), делятся между всеми экземплярами. Атрибуты, присваиваемые self, — у каждого свои:

main.py
Output
Click Run to see the output here.

Используй атрибуты класса для по-настоящему общих значений — констант, счётчиков, конфигов. Всё, что специфично экземпляру, — в __init__.

Наследование

Класс может наследовать другой, получая его методы и атрибуты даром, и добавлять или переопределять по нужде:

main.py
Output
Click Run to see the output here.

super() даёт доступ к родителю — часто используется внутри __init__, чтобы инициализировать родительские атрибуты перед добавлением своих:

main.py
Output
Click Run to see the output here.

Наследование полезно, но легко пере-использовать. Начинающий питонист часто тянется к нему, когда композиция — держать объект как атрибут — понятнее. Начинай с плоской структуры классов и вводи наследование только при настоящем отношении «is-a».

Dataclasses: более приятный дефолт для записей

Когда класс в основном нужен для пары атрибутов с нормальным равенством и репрезентацией, @dataclass избавляет от бойлерплейта:

main.py
Output
Click Run to see the output here.

Сравни с ручной записью __init__, __repr__ и __eq__. Dataclass — правильный первый выбор, когда иначе ты написал бы class Thing только с __init__, проставляющим атрибуты.

Property: вычисляемые атрибуты

Иногда хочется «атрибут», который на самом деле вычисляется. @property делает это похожим на обращение к атрибуту:

main.py
Output
Click Run to see the output here.

Используй 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. Если у тебя одна функция — ей не нужен класс-обёртка. Тянись к классам, когда у тебя и состояние, и поведение связаны вместе — особенно если будет много экземпляров одного рода.

Финальный пример

Маленький файло-подобный лог-буфер:

main.py
Output
Click Run to see the output here.

Обрати внимание на __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-программы используют классы скупо, предпочитая обычные функции и структуры данных там, где это возможно.

Учитесь программировать с Coddy

НАЧАТЬ