Ответ
__str__ и __repr__ — это методы для получения строкового представления объекта, но они предназначены для разной аудитории и целей.
| Метод | Целевая аудитория | Основная цель | Вызывается функциями | Требования |
|---|---|---|---|---|
__str__(self) |
Конечные пользователи, для удобочитаемого вывода. | Предоставить красивое, неформальное, понятное строковое представление. | print(), str(), f-строки (неявно). |
Читаемость и информативность для человека. |
__repr__(self) |
Разработчики, для отладки и логгирования. | Предоставить однозначное, формальное, максимально полное представление, желательно позволяющее воссоздать объект. | repr(), вывод в интерактивной консоли, логгирование. |
Однозначность. Идеально, если eval(repr(obj)) == obj. |
Простое правило: __repr__ — для разработчика (что это за объект?), __str__ — для пользователя (как это показать?).
Наглядный пример:
class Project:
def __init__(self, name, language, version):
self.name = name
self.language = language
self.version = version
def __str__(self):
# Удобочитаемо для пользователя
return f"Project '{self.name}' (v{self.version})"
def __repr__(self):
# Точное и полное представление для разработчика
# Обратите внимание на экранирование строки name!
return f"Project(name='{self.name}', language='{self.language}', version={self.version})"
# Создаем объект
my_project = Project("Alpha", "Python", 1.5)
print("Using print() / str():")
print(my_project) # Неявно вызывает __str__
print(str(my_project)) # Явный вызов __str__
# Вывод: Project 'Alpha' (v1.5)
print("nUsing repr() or in console:")
print(repr(my_project)) # Явный вызов __repr__
# В интерактивной консоли просто `my_project` выведет это же.
# Вывод: Project(name='Alpha', language='Python', version=1.5)
# Идеальное свойство repr: возможность воссоздания (не всегда достижимо)
try:
# Для простых классов repr может быть исполняемым кодом
copy_project = eval(repr(my_project))
print(f"nCopy created: {copy_project.name}")
except:
pass
Важные детали:
- Fallback: Если метод
__str__не определен, Python использует__repr__в качестве запасного варианта (например, вprint()). Поэтому всегда определяйте__repr__— это хороший тон. - Для коллекций:
print(list)использует__repr__для элементов списка, а не__str__. - Стандартный
__repr__по умолчанию (<__main__.Project object at 0x7f8a1c2b4d90>) бесполезен для отладки. Всегда переопределяйте его.
Правило большого пальца: Сначала напишите информативный __repr__. Затем, если нужен особый формат для вывода пользователю, добавьте __str__.
Ответ 18+ 🔞
А, ну вот, опять эти два метода, которые всех в ступор вгоняют. Слушай, представь себе: ты написал какой-нибудь класс, там Project какой-нибудь, и он у тебя в коде как чёрный ящик лежит. А потом ты его в консоль выводишь, и тебе показывают какую-то хуйню вроде <__main__.Project object at 0x7f8a1c2b4d90>. Ну и чё это, блядь, такое? Это пиздец, а не информация. Вот для этого и нужны __str__ и __repr__ — чтобы этот ящик не таким страшным был.
Так, поехали по-простому. __str__ — это типа твоя парадная форма. Ты надеваешь её, когда идешь к людям, которые нихуя не шарят в коде. Чтобы им красиво и понятно показать: "Вот, смотрите, это проект 'Альфа', версия 1.5". Красиво, коротко, без лишних деталей. Его вызывает print() или str().
А __repr__ — это уже для своих, для таких же задротов, как ты. Это как техпаспорт на объект, или даже лучше — как инструкция по его сборке. Тут уже надо вывалить всё: и имя, и язык, и версию, да так, чтобы другой программист глянул и сразу понял, что за зверь перед ним. А в идеале — чтобы можно было скопировать этот текст, вставить в код, и получился бы такой же объект. Его вызывает repr() или просто пишешь имя объекта в консоли.
Вот смотри, как это в жизни выглядит, ёпта:
class Project:
def __init__(self, name, language, version):
self.name = name
self.language = language
self.version = version
def __str__(self):
# Это типа для красоты, для юзеров
return f"Project '{self.name}' (v{self.version})"
def __repr__(self):
# А это уже по-взрослому, для отладки. Смотри, как всё подробно.
return f"Project(name='{self.name}', language='{self.language}', version={self.version})"
# Ну и создаём объект, чего уж там
my_project = Project("Alpha", "Python", 1.5)
print("Смотри, что print() делает:")
print(my_project) # Тут вызовется __str__
# Выведет: Project 'Alpha' (v1.5) — красиво и понятно.
print("nА теперь смотри, что repr() говорит:")
print(repr(my_project)) # А тут уже __repr__ в деле
# Выведет: Project(name='Alpha', language='Python', version=1.5) — всё по полочкам.
# И самое офигенное, что если repr написан хорошо, то можно даже так:
try:
copy_project = eval(repr(my_project)) # Берем строку от repr и делаем из неё объект!
print(f"nСмотри, клон создали: {copy_project.name}")
except:
pass
Вот и вся магия. Но есть важные фишки, которые надо помнить, а то наебнёшься.
- Запасной парашют. Если ты такой хитрожопый и не написал
__str__, то Python, когда его попросят напечатать твой объект, пойдёт и вызовет__repr__вместо него. Поэтому всегда пиши__repr__, это как базовая гигиена. Иначе будешь получать тот самый дефолтный пиздец с адресом в памяти, от которого пользы — ноль ебать. - Коллекции — они особенные. Ты думаешь, положил объекты в список, вывел список, и для каждого элемента вызовется
__str__? Хуй там!print([obj1, obj2])использует__repr__для каждого элемента внутри. Так что если твой__repr__кривой, то и в списке всё будет выглядеть как говно. - Правило простое, как три копейки. Сначала всегда пиши нормальный, подробный
__repr__. Потом, если тебе вдруг понадобится какая-то особая, красивая строка для логов или интерфейса — вот тогда уже добавляй__str__. А так —__repr__твой главный друг на отладке.
Короче, запомни: __repr__ — чтобы понять, что за хуйня. __str__ — чтобы красиво показать, какая это хуйня.