Печать объектов: __str__ vs __repr__ в Python

Печать объектов: __str__ vs __repr__ в Python

@python_quiz

Разберем этот квиз

Коротко — почему вывод будет таким, а не иначе. Разберём строку кода, как она создаёт класс и какой метод что выводит.

Код из квиза

python

Что здесь происходит:

  • 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')]

Итого: сначала строка в верхнем регистре, затем список с репрезентацией объекта.

Демонстрация вывода

python

Анализ вариантов ответов (читаем и сравниваем)

  • "Сначала '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__ были согласованы, например:
python

Или заставить __repr__ делегировать __str__ (или наоборот), если нужен единый формат.

Вывод

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

Report Page