Представление объектов: __str__ и __repr__
Хорошее строковое представление объекта экономит время на отладке и делает выводы понятными. В Python за это отвечают два специальных метода:
__repr__— «официальное» представление для разработчика: максимально точное и однозначное. Часто похоже на конструктор:ClassName(field=value, ...).__str__— «человеческое» представление для пользователя: коротко и приятно читается.
Если __str__ не определён, Python будет использовать __repr__ и для print(). Списки, словари и отладчики почти всегда используют именно __repr__ элементов.
Базовый пример: оба метода вместе
class HockeyPlayer:
def __init__(self, name, age, team):
self.name = name
self.age = age
self.team = team
def __repr__(self):
# Для разработчика: явно показываем поля, строки — через !r
return f"HockeyPlayer(name={self.name!r}, age={self.age}, team={self.team!r})"
def __str__(self):
# Для пользователя: компактно и по смыслу
return f"{self.name} — {self.team}, {self.age} лет"
p = HockeyPlayer('Иван', 17, 'Метеор')
print(p) # __str__
print(repr(p)) # __repr__ явно
print([p]) # контейнеры используют __repr__ элементов
print(f"{p}") # f-строка по умолчанию использует __str__
print(f"{p!r}") # !r берёт __repr__
Иван — Метеор, 17 лет
HockeyPlayer(name='Иван', age=17, team='Метеор')
[HockeyPlayer(name='Иван', age=17, team='Метеор')]
Иван — Метеор, 17 лет
HockeyPlayer(name='Иван', age=17, team='Метеор')
Только __repr__: печать всё равно работает
class PlayerReprOnly:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"PlayerReprOnly(name={self.name!r})"
x = PlayerReprOnly('Иван')
print(x) # падать не будет — print возьмёт __repr__
print(repr(x)) # то же самое явно
PlayerReprOnly(name='Иван')
PlayerReprOnly(name='Иван')
Типичные ошибки: возвращать нужно строку
Оба метода обязаны возвращать именно строку. Любой другой тип — ошибка.
class BadStr:
def __str__(self):
return 123 # ошибка: должен быть str
try:
print(BadStr())
except TypeError as e:
print('Ошибка:', e)
Ошибка: __str__ returned non-string (type int)
Мини-памятка
- Делайте
__repr__максимально информативным и однозначным (лучше в виде «конструктора»). - Делайте
__str__кратким и дружелюбным — для пользовательского вывода. - В f-строках
f"{obj}"использует__str__, аf"{obj!r}"—__repr__. - Если
__str__отсутствует,print(obj)покажет__repr__. - Списки и другие контейнеры печатают элементы через их
__repr__.