Шаг 60.
Python: тонкости программирования. Классы и ООП. Преобразование строк (использование __repr__). Метод __str__ против __repr__

    На этом шаге мы сравним эти два дандер-метода.

    Нужно сказать, что наша история преобразования строк на этом не заканчивается. Вы заметили, что просмотр объекта my_car в сеансе интерпретатора по-прежнему дает этот странный результат <__main__.Car object at 0x00000182B64C81C0>?

    Это произошло, потому что фактически имеется два дандер-метода, которые управляют тем, как объекты преобразовываются в строковые значения в Python 3. Первый, __str__, и вы только что с ним познакомились.

    Второй, __repr__, и характер его работы аналогичен методу __str__, но он используется в других ситуациях. (В Python 2.x также имеется метод __unicode__, которого мы коснемся чуть позже.)

    Ниже приведен простой эксперимент для "обкатки" ситуации, когда используется метод __str__ или __repr__. Давайте переопределим наш автомобильный класс таким образом, чтобы он содержал оба дандер-метода для преобразования в строковое значение с результатами, которые легко различить:

>>> class Car:
	def __init__(self, color, mileage):
		self.color = color
		self.mileage = mileage
	def __repr__(self):
		return '__repr__ для объекта Car'
	def __str__(self):
		return '__str__ для объекта Car'

    Теперь, когда вы поэкспериментируете с приведенными выше примерами, вы поймете, какой метод управляет результатом преобразования строк в каждом случае:

>>> my_car = Car('красный', 37281)
>>> print(my_car)
__str__ для объекта Car
>>> '{}'.format(my_car)
'__str__ для объекта Car'
>>> my_car
__repr__ для объекта Car

    Этот эксперимент подтверждает, что в результате инспектирования объекта в сеансе интерпретатора Python просто печатается результат выполнения метода __repr__ объекта.

    Интересно отметить, что в контейнерах, таких как списки и словари, для представления содержащихся в них объектов всегда используется результат метода __repr__, даже если вызвать функцию str() с самим контейнером:

>>> str([my_car])
'[__repr__ для объекта Car]'

    Что касается ручного выбора между обоими методами преобразования строк, например, чтобы яснее выразить замысел вашего программного кода, то лучше всего использовать встроенные функции str() и repr(). Их применение предпочтительнее прямых вызовов метода __str__ или __repr__ объекта, поскольку они воспринимаются лучше и дают тот же самый результат:

>>> str(my_car)
'__str__ для объекта Car'
>>> repr(my_car)
'__repr__ для объекта Car'

    Даже по завершении этого исследования вам, возможно, будет любопытно узнать, какова "реальная" разница между методами __str__ и __repr__. На вид они оба служат одной и той же цели, поэтому может быть не ясно, когда использовать каждый из них.

    В случае таких вопросов обычно неплохо взглянуть на то, что делает стандартная библиотека Python. Самое время поставить еще один эксперимент. Мы создадим объект datetime.date и выясним, каким образом в нем используются методы __repr__ и __str__ для управления преобразованием строк:

>>> import datetime
>>> today = datetime.date.today()

    Результат метода __str__ объекта даты должен быть прежде всего удобочитаемым. Он призван возвращать легко воспринимаемое человеком сжатое текстовое представление - то, что вы спокойно можете показать пользователю. По этой причине, когда мы вызываем функцию str() с объектом даты, мы получаем нечто похожее на формат даты по ISO:

>>> str(today)
'2025-10-29'

    В случае с методом __repr__ идея состоит в том, что его результат должен быть прежде всего однозначным. Результирующее строковое значение больше предназначено для разработчиков как средство отладки. И в связи с этим он должен максимально четко выражать то, чем этот объект является. Именно поэтому при вызове функции repr() с объектом вы получите более подробный результат. Он даже будет содержать полное имя модуля и класса:

>>> repr(today)
'datetime.date(2025, 10, 29)'

    Возвращаемое методом __repr__ строковое значение можно скопировать и вставить в консоль интерпретатора и исполнить его как допустимый фрагмент кода Python, чтобы воссоздать оригинальный объект даты. Этот изящный подход и хороший целевой ориентир следует иметь в виду при написании своих собственных функций repr(). С другой стороны, похоже, довольно-таки трудно найти применение такой функции на практике. Она не будет стоить затраченных на нее усилий и просто создаст для вас дополнительную работу. Формулируемое эмпирическое правило заключается в том, чтобы делать свои строки __repr__ однозначными и полезными для разработчиков, но мы не рассчитываем, что они смогут восстанавливать полное состояние объекта.

    На следующем шаге мы попытаемся обосновать необходимость наличия в классе метода __repr__.




Предыдущий шаг Содержание Следующий шаг