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

Представьте чертёж на стене. На нём написано Player и перечислены поля: имя и очки. По чертежу заполняют карточки игроков: на первой имя Ann, на второй — Bob. Чертёж один, карточек сколько угодно, и у каждой свои значения.
В 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 позволяет описать игрока в одном месте: какие у него данные и что с ним можно делать.
Класс и экземпляры
Класс — описание нового типа объектов, тот самый чертёж. Объект этого типа называют экземпляром класса: это заполненная карточка. Переменные, привязанные к экземпляру, — его атрибуты, поля карточки. Функции, объявленные внутри класса, — его методы, то есть действия с карточкой.
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"):
- Вызов
Player("Ann")создаёт новый пустой объект — чистую карточку. - Python вызывает его метод
__init__: вselfпопадает этот объект, вname— строка"Ann". - Строки
self.name = nameиself.score = 0создают атрибуты экземпляра. - Готовый объект становится результатом вызова, и имя
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, и меняются очки только этого объекта.
1class Player:2 def __init__(self, name):3 self.name = name4 self.score = 05 6 def add_points(self, n):7 self.score += n8 9 10ann = Player("Ann")11bob = Player("Bob")12ann.add_points(5)13Player.add_points(bob, 2)14print(ann.score, bob.score)
Вызов Player("Ann") создаёт новый объект и передаёт его в __init__.
Каждый вызов класса создаёт отдельный экземпляр со своими атрибутами. Атрибуты читают и меняют через точку и снаружи класса:
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:
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)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 и подпишись на канал — откроются все уроки.