'[__repr__ для объекта Car]'
Что касается ручного выбора между обоими методами преобразования
строк, например, чтобы яснее выразить замысел вашего программного
кода, то лучше всего использовать встроенные функции
str()
и
repr()
.
Их применение предпочтительнее прямых вызовов метода
__str__
или
__repr__
объекта, поскольку они воспринимаются лучше и дают тот же
самый результат:
>>> str(my_car)
'__str__ для объекта Car'
>>> repr(my_car)
'__repr__ для объекта Car'
Даже по завершении этого исследования вам, возможно, будет любопытно
узнать, какова «реальная» разница между методами
__str__
и
__repr__
.
На вид они оба служат одной и той же цели, поэтому может быть не ясно,
когда использовать каждый из них.
4 .2 . Преобразование строк (каждому классу по __repr__) 109
В случае таких вопросов обычно неплохо взглянуть на то, что делает
стандартная библиотека Python. Самое время поставить еще один экс-
перимент. Мы создадим объект
datetime.date
и выясним, каким образом
в нем используются методы
__repr__
и
__str__
для управления преоб-
разованием строк:
>>> import datetime
>>> today = datetime.date.today()
Результат метода
__str__
объекта даты должен быть прежде всего удо-
бочитаемым. Он призван возвращать легко воспринимаемое человеком
сжатое текстовое представление — то, что вы спокойно можете показать
пользователю. По этой причине, когда мы вызываем функцию
str()
с объ-
ектом даты, мы получаем нечто похожее на формат даты по ISO:
>>> str(today)
'2017-02-02'
В случае с методом
__repr__
идея состоит в том, что его результат должен
быть прежде всего однозначным. Результирующее строковое значение
больше предназначено для разработчиков как средство отладки. И в
связи с этим он должен максимально четко выражать то, чем этот объект
является. Именно поэтому при вызове функции
repr()
с объектом вы
получите более подробный результат. Он даже будет содержать полное
имя модуля и класса:
>>> repr(today)
'datetime.date(2017, 2, 2)'
Возвращаемое методом
__repr__
строковое значение можно скопировать
и вставить в консоль интерпретатора и исполнить его как допустимый
фрагмент кода Python, чтобы воссоздать оригинальный объект даты. Этот
изящный подход и хороший целевой ориентир следует иметь в виду при
написании своих собственных функций
repr
.
С другой стороны, я полагаю, что довольно-таки трудно найти приме-
нение такой функции на практике. Она не будет стоить затраченных на
нее усилий и просто создаст для вас дополнительную работу. Мое эмпи-
рическое правило заключается в том, чтобы делать свои строки
__repr__
110 Глава 4 • Классы и ООП
однозначными и полезными для разработчиков, но я не рассчитываю,
что они смогут восстанавливать полное состояние объекта.
Почему каждый класс нуждается в __repr__
Если опустить метод
__str__
, то Python в поисках
__str__
отыграет назад
к результату
__repr__
. По этой причине я рекомендую добавлять в свои
классы всегда, по крайней мере, метод
__repr__
. Это обеспечит полезный
результат преобразования строк почти во всех случаях при минимуме
работы по его реализации.
Ниже показано, как можно быстро и эффективно добавить в свои классы
элементарную поддержку преобразования строк. Для нашего класса
Car
мы могли бы начать с приведенного ниже метода
__repr__
:
def __repr__(self):
return f'Car({self.color!r}, {self.mileage!r})'
Обратите внимание на то, что я использую флаг преобразования
!r
,
тем самым гарантируя, что в выводимом строковом значении вместо
str(self.color)
и
str(self.mileage)
будут использованы
repr(self.
color)
и
repr(self.mileage)
.
Это работает безупречно, но оборотной стороной является то, что мы по-
вторили имя класса в форматной строке. Для того чтобы избежать этого
повторения, здесь можно применить трюк с использованием атрибута
__calss__.__name__
объекта. Данный атрибут всегда будет зеркально
отображать имя класса в виде строки.
Преимущество состоит в том, что вам не придется модифицировать реа-
лизацию метода
__repr__
, когда имя класса изменится. Это позволяет
беспрепятственно придерживаться принципа DRY, то есть «не повто-
ряйся»:
def __repr__(self):
return (f'{self.__class__.__name__}('
f'{self.color!r}, {self.mileage!r})')
4 .2 . Преобразование строк (каждому классу по __repr__) 111
Оборотной стороной этой реализации является то, что форматная строка
довольно длинная и громоздкая. Но при условии выверенного формати-
рования вы сможете сохранить свой исходный код аккуратным и соот-
ветствующим правилам PEP 8.
Во время инспектирования объекта или непосредственного вызова функ-
ции
repr()
с объектом при наличии приведенной выше реализации метода
__repr__
мы получаем полезный результат:
>>> repr(my_car)
Do'stlaringiz bilan baham: |