Печать объектов: __str__ vs __repr__ в Python
@python_quizРазберем этот квиз
Коротко — почему вывод будет таким, а не иначе. Разберём строку кода, как она создаёт класс и какой метод что выводит.
Код из квиза

Что здесь происходит:
- type(...) динамически создаёт класс User с тремя методами, заданными как лямбда-функции.
__init__сохраняет имя в атрибуте name.__repr__возвращает строку в видеUser('alex')(используется !r — репрезентация значения).__str__возвращает имя в верхнем регистре:ALEX.- Создаётся экземпляр с именем
'alex'.
Почему именно такой вывод?
- print(u) вызывает функцию str(u). Если у объекта определён
__str__, он и используется. В нашем случае__str__возвращает имя в верхнем регистре, значит будет выведено:
ALEX
- При печати контейнеров (списков, кортежей и т.д.) Python использует repr() для элементов, потому что контейнеры отображаются с помощью их собственных представлений, а элементы в них вставляются в виде их repr-представления. Значит print([u]) даст:
[User('alex')]
Итого: сначала строка в верхнем регистре, затем список с репрезентацией объекта.
Демонстрация вывода

Анализ вариантов ответов (читаем и сравниваем)
- "Сначала 'alex', затем ['alex']"
- Неверно: print(u) не использует значение как есть через атрибут name (и не печатает в том же регистре). Кроме того, контейнер использует repr, а не str, так что элементы не будут напечатаны как строки имени.
- "Сначала 'ALEX', затем [User('alex')]"
- Соответствует поведению: print(u) -> __str__ -> ALEX; print([u]) -> контейнер использует __repr__ -> User('alex') внутри списка.
- "Сначала 'ALEX', затем ['ALEX']"
- Неверно: контейнеры не используют __str__ для элементов, поэтому элемент не будет напечатан как 'ALEX'.
- "Сначала 'User(\"alex\")', затем [User(\"alex\")]"
- Неверно: print(u) использует __str__, а не __repr__, поэтому первая строка не будет в виде User('alex').
Дополнительные замечания и варианты
- Если
__str__не определён, print(obj) использует__repr__. - Если
__repr__не определён, контейнеры будут показывать стандартную репрезентацию вида <__main__.User object at 0x...>. - Можно сделать так, чтобы
__repr__и__str__были согласованы, например:

Или заставить __repr__ делегировать __str__ (или наоборот), если нужен единый формат.
Вывод
При печати одиночного объекта вызывается __str__ (если он есть), а при печати контейнера элементы вставляются через их __repr__. В приведённом примере это даёт сначала ALEX, а затем [User('alex')].