До сих пор экземпляры своих классов мы не печатали — только их атрибуты. И не зря: без подготовки Python печатает экземпляр так:
>>> latte = Product("Латте", 220)
>>> latte
<__main__.Product object at 0x10a3f2b50>
Имя класса и адрес объекта в памяти — для отладки почти бесполезно, а адрес к тому же меняется при каждом запуске. Научим класс выглядеть понятно.
Магические методы
__init__ — не единственный метод с двумя подчёркиваниями. Таких методов десятки, и все они устроены
одинаково: Python вызывает их сам, когда с объектом делают что-то встроенное. len(x) вызывает
x.__len__(), print(x) — x.__str__(), а __init__ — создание экземпляра. Их называют магическими
методами (special methods; их ещё называют dunder — от double underscore). Объявите такой метод в своём
классе — и встроенная операция заработает с вашими объектами.
word = "латте"
print(len(word))
print(word.__len__()) # это и делает len5 5
__repr__: представление для отладки
Метод __repr__ возвращает строковое представление (representation) объекта для программиста. Его
показывает Jupyter для значения последней строки ячейки, его используют списки и словари, когда печатают
свои элементы, и его возвращает встроенная функция repr(). Хорошее представление однозначно и, по
возможности, похоже на код, который создаёт такой же объект:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __repr__(self):
return f"Product(name={self.name!r}, price={self.price})"
latte = Product("Латте", 220)
print(repr(latte))
print([latte, Product("Чай", 120)])
latte # значение последней строки ячейки показывается через reprProduct(name='Латте', price=220) [Product(name='Латте', price=220), Product(name='Чай', price=120)]
Product(name='Латте', price=220)
Обратите внимание на !r в f-строке: {self.name!r} вставляет не саму строку, а её repr — с кавычками.
Без них Product(Латте, 220) уже не похоже на код.
Допишите класс Drink: метод __repr__ возвращает строку вида Drink('Латте', 220) — имя класса, название
в кавычках и цену.
!r из демонстрации.f"Drink(…, …)" с self.name!r и self.price внутри.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Drink:
def __init__(self, name, price):
self.name = name
self.price = price
def __repr__(self):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Drink:
def __init__(self, name, price):
self.name = name
self.price = price
def __repr__(self):
return f"Drink({self.name!r}, {self.price})"__str__: для людей
Метод __str__ возвращает текст для людей — для print, str() и f-строк. Он не обязан быть похож на
код. Если __str__ в классе нет, Python использует __repr__:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __repr__(self):
return f"Product(name={self.name!r}, price={self.price})"
def __str__(self):
return f"{self.name} за {self.price} ₽"
latte = Product("Латте", 220)
print(latte)
print(str(latte), "|", repr(latte))
print(f"Сегодня советуем: {latte}")
latteЛатте за 220 ₽ Латте за 220 ₽ | Product(name='Латте', price=220) Сегодня советуем: Латте за 220 ₽
Product(name='Латте', price=220)
Допишите класс Order: __repr__ возвращает Order(17, 640) — номер и сумму, а __str__ — текст для
кассира: Заказ №17 на 640 ₽.
__repr__ похож на код создания заказа, __str__ — на фразу для кассира; оба собирают строку из self.number и self.total.return f"Заказ №{self.number} на {self.total} ₽" — это __str__.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Order:
def __init__(self, number, total):
self.number = number
self.total = total
def __repr__(self):
...
def __str__(self):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Order:
def __init__(self, number, total):
self.number = number
self.total = total
def __repr__(self):
return f"Order({self.number}, {self.total})"
def __str__(self):
return f"Заказ №{self.number} на {self.total} ₽"У класса Order из упражнения есть и __str__, и __repr__. Что напечатает print([Order(17, 640)])?
print вызывает __str__ у самого списка, а список собирает свой текст из repr элементов. Поэтому внутри списка, словаря и кортежа всегда видно представление для отладки.repr и str в f-строках
В f-строке {x} даёт str(x), а {x!r} — repr(x). Первое — для сообщений людям, второе — для журналов
и сообщений об ошибках, где важно точно видеть значение:
Для заказа order составьте две строки: message — "Готов: Заказ №17 на 640 ₽" для экрана выдачи (через
__str__) и log — "создан Order(17, 640)" для журнала (через __repr__). Используйте f-строки с самим
объектом, без обращения к его атрибутам.
{order} в f-строке вызывает __str__, а что вызовет __repr__ — сказано в абзаце выше.f"создан {order!r}".Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
order = Order(17, 640)
message = ...
log = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
order = Order(17, 640)
message = f"Готов: {order}"
log = f"создан {order!r}"Правило на будущее: у каждого своего класса должен быть __repr__ — отладка без него мучительна.
__str__ — когда объекту нужен отдельный «человеческий» вид.