Программирование и IT
Python: классы
Класс описывает, из каких данных состоит объект и что он умеет делать. Конструктор `__init__` заполняет новый объект, `self` — ссылка на него самого. Ниже — минимальный рабочий класс, разница между атрибутом класса и атрибутом экземпляра и способы сделать код короче.
В этой статье
Минимальный класс#
=
=
return f
=
# Война и мир, 1300 с.
# 1300
Имя класса пишут с заглавной, слова слитно (UserProfile) — так принято в
PEP 8. Вызов Book(...) создаёт объект и передаёт аргументы в __init__.
Что такое self и почему он первый#
self — не ключевое слово, а обычный первый параметр, в который Python
подставляет сам объект. Запись b.summary() равнозначна Book.summary(b).
Поэтому каждый метод экземпляра объявляют с self, а обращение к данным идёт
через него: self.pages, а не просто pages.
Две ошибки растут отсюда. Первая — забыть self в объявлении:
return
# TypeError: Bad.show() takes 0 positional arguments but 1 was given
Вторая — писать в __init__ return. Конструктор ничего не возвращает; любая
попытка вернуть значение, кроме None, даёт TypeError.
Атрибут класса и атрибут экземпляра#
Атрибут, объявленный прямо в теле класса, принадлежит классу и общий для всех
объектов. Атрибут, присвоенный через self, принадлежит одному объекту.
= 0 # общий для всех
= 0 # свой у каждого
+= 1
+= 1
, = ,
; ;
# 2 1 3
Ловушка — изменяемый атрибут класса. Список, объявленный в теле класса, один на
всех:
= # так делать не надо
, = ,
# ['хлеб']
Правильно создавать такой список в __init__: self.items = [].
Как объект выглядит при печати#
По умолчанию print(obj) даёт что-то вроде <__main__.Book object at 0x10a3f...>. Читаемый вид задаёт __repr__:
, = ,
return f
return ==
# Point(1, 2)
# [Point(0, 0)]
# True
__repr__ используется и при печати самого объекта, и внутри списков, поэтому
из двух методов (__str__ и __repr__) начинать стоит именно с него. Без
__eq__ два одинаковых по данным объекта считаются разными.
property, classmethod и dataclass#
Вычисляемое свойство пишется как метод с декоратором @property, а
используется как обычный атрибут — без скобок:
, = ,
return *
=
# 12
@classmethod даёт альтернативный способ создать объект: первый параметр —
сам класс, обычно его называют cls. @staticmethod — просто функция,
живущая рядом с классом.
Когда класс нужен только для хранения полей, короче взять dataclass: он сам
напишет __init__, __repr__ и __eq__.
:
: = 0
=
# User(name='Аня', age=30)
# True
Практика: опиши класс BankAccount с полем баланса, методами пополнения и
списания и свойством is_empty; при попытке снять больше, чем есть, бросай
ValueError — как это делается, разобрано в статье про
исключения. Наследование и остальные принципы —
в статье про ООП.
План по этапам
- Класс с двумя полямиОбъявить класс, заполнить поля в __init__, создать два объекта и вывести их поля.
- Метод, который считаетДобавить метод, использующий self, и вызвать его у обоих объектов.
- Сравнить атрибутыЗавести атрибут класса и атрибут экземпляра, изменить оба и посмотреть на разницу.
- Читаемая печатьНаписать __repr__ и убедиться, что объект нормально выглядит внутри списка.
- Сократить до dataclassПереписать класс-хранилище через @dataclass и сравнить объём кода.
Начать изучать эту тему у себя
План ляжет в твой репозиторий: отмечай этапы, веди конспект — история изменений покажет, как ты продвинулся.
Проверь себя
1.У класса A конструктор «def __init__(self, x): self.x = x». Что выведет print(A(5).x)?
2.Класс Cart имеет атрибут класса items = []. После x = Cart(); y = Cart(); x.items.append(1) чему равно len(y.items)?
3.Какой метод нужно определить, чтобы print(obj) показывал читаемое описание объекта?
4.Как обратиться к свойству, объявленному с @property, по имени area?
Источники
-
Классы в учебнике PythonОфициальный разбор class, self, области видимостибесплатно
-
Модуль dataclassesАвтоматические __init__, __repr__ и __eq__бесплатно
-
PEP 8 — стиль кодаПравила именования классов и методовбесплатно
Было полезно?