Перейти к содержимому
Теория · Классы · урок 1 из 11

Классы и объекты

Чему вы научитесь

Чему вы научитесь:

  • описывать свой тип данных классом и создавать по нему объекты;
  • объяснять, что такое self и почему у метода на один параметр больше, чем у вызова;
  • задавать, как объект печатается и сравнивается, через __str__, __repr__ и __eq__;
  • отличать атрибут класса от атрибута экземпляра, наследовать классы и писать классы данных.
Чертёж Player на стене и две заполненные по нему карточки, на первой имя Ann

Представьте чертёж на стене. На нём написано Player и перечислены поля: имя и очки. По чертежу заполняют карточки игроков: на первой имя Ann, на второй — Bob. Чертёж один, карточек сколько угодно, и у каждой свои значения.

В Python такой чертёж называется классом. Но сначала посмотрим, как обойтись без него. Данные об игроке можно хранить в словаре, а действия с ними писать отдельными функциями:

Python
def add_points(player, n):
    player["score"] += n


ann = {"name": "Ann", "score": 0}
add_points(ann, 5)
print(ann["name"], ann["score"])  # Ann 5

Программа работает, но у неё есть два слабых места:

  • какие ключи есть у игрока, видно только там, где создан словарь;
  • функция add_points примет любой словарь, даже без ключа "score".

Python позволяет описать игрока в одном месте: какие у него данные и что с ним можно делать.

Класс и экземпляры

Класс — описание нового типа объектов, тот самый чертёж. Объект этого типа называют экземпляром класса: это заполненная карточка. Переменные, привязанные к экземпляру, — его атрибуты, поля карточки. Функции, объявленные внутри класса, — его методы, то есть действия с карточкой.

Python
class Player:
    def __init__(self, name):
        self.name = name
        self.score = 0

    def add_points(self, n):
        self.score += n


ann = Player("Ann")
ann.add_points(5)
print(ann.name, ann.score)  # Ann 5

Давайте разберём, что происходит в строке ann = Player("Ann"):

  1. Вызов Player("Ann") создаёт новый пустой объект — чистую карточку.
  2. Python вызывает его метод __init__: в self попадает этот объект, в name — строка "Ann".
  3. Строки self.name = name и self.score = 0 создают атрибуты экземпляра.
  4. Готовый объект становится результатом вызова, и имя ann ссылается на него.

Не каждый атрибут приходит из параметра: очки любого нового игрока начинаются с 0. Возвращать объект из __init__ не нужно: результатом вызова Player("Ann") становится он сам.

Имена классов пишут с заглавной буквы и без подчёркиваний: Player, BankAccount. Методы отделяют друг от друга одной пустой строкой.

Параметр self

Посмотрите на вызов ann.add_points(5). В скобках один аргумент, а у метода два параметра. Второй аргумент Python добавляет сам: объект перед точкой он передаёт первым, в self.

Запись ann.add_points(5) означает то же самое, что Player.add_points(ann, 5). Метод хранится в классе один на всех, а через self он узнаёт, с чьей карточкой работать. Поэтому self.score += n меняет очки именно того экземпляра, для которого метод вызвали.

Нажмите «Следующий шаг» и следите за рамкой add_points. В первом вызове self — это ann, во втором — bob, и меняются очки только этого объекта.

ВживуюОдин метод, два объекташаг 1 из 13 · рамок: 1

Вызов Player("Ann") создаёт новый объект и передаёт его в __init__.

Следите, какой объект лежит в self

Каждый вызов класса создаёт отдельный экземпляр со своими атрибутами. Атрибуты читают и меняют через точку и снаружи класса:

Python
bob = Player("Bob")
bob.add_points(2)
print(ann.score, bob.score)  # 5 2
bob.score = 10
print(ann.score, bob.score)  # 5 10

Здесь аналогия с карточками заканчивается. Метод не написан на каждой карточке: он хранится один раз в классе, на чертеже. Карточку, с которой ему работать, он каждый раз получает через self.

На собеседовании часто спрашивают: «Что такое self?» Ответ из трёх частей:

  • self — первый параметр метода, в нём лежит объект, для которого метод вызвали;
  • Python передаёт его сам: ann.add_points(5) — это Player.add_points(ann, 5);
  • self — не ключевое слово, а договорённость об имени, но пишут его всегда.

Частая ошибка

В объявлении метода забывают параметр self:

Python
class Player:
    def __init__(self, name):
        self.name = name
        self.score = 0

    def add_points(n):  # ✗
        self.score += n


ann = Player("Ann")
ann.add_points(5)
TEXT
TypeError: Player.add_points() takes 1 positional argument but 2 were given

В вызове ann.add_points(5) Python передаёт два аргумента — ann и 5, а метод принимает один. Первым параметром каждого метода пишите self.

Главное

  • Класс описывает новый тип объектов, а каждый вызов Player("Ann") создаёт отдельный экземпляр.
  • __init__ получает новый объект в self и создаёт его атрибуты.
  • ann.add_points(5) — это Player.add_points(ann, 5): объект перед точкой попадает в self.
  • Метод у всех экземпляров общий, а атрибуты у каждого свои.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом