В чем разница между __str__
и __repr__
в Python?
__str__
(читается как «строка dunder (двойное подчеркивание)») и __repr__
(читается как «dunder-repper» (для «представление»)) оба специальных метода, которые возвращают строки на основе состояния предмет.
__repr__
обеспечивает резервное копирование, если отсутствует __str__
.
Таким образом, сначала нужно написать __repr__
, который позволяет вам восстановить экземпляр эквивалентного объекта из строки, которую он возвращает, например. используя eval
или набирая его символ за символом в оболочке Python.
В любое время позже можно написать __str__
для читаемого пользователем строкового представления экземпляра, когда кто-то считает это необходимым.
__str__
Если вы напечатаете объект или передадите его format
, str.format
или str
, то, если определен метод __str__
, будет вызван этот метод, в противном случае будет использоваться __repr__
,
__repr__
Метод __repr__
вызывается встроенной функцией repr
и является тем, что отображается в вашей оболочке python, когда он вычисляет выражение, возвращающее объект.
Поскольку он предоставляет резервную копию для __str__
, если вы можете написать только одну, начните с __repr__
Вот встроенная справка по repr
:
repr(...)
repr(object) -> string
Return the canonical string representation of the object.
For most object types, eval(repr(object)) == object.
То есть, для большинства объектов, если вы напечатаете то, что напечатано repr
, вы сможете создать эквивалентный объект. Но это не реализация по умолчанию.
Реализация по умолчанию __repr__
Объект по умолчанию __repr__
( C источник Python ) что-то вроде:
def __repr__(self):
return '<{0}.{1} object at {2}>'.format(
self.__module__, type(self).__name__, hex(id(self)))
Это означает, что по умолчанию вы будете печатать модуль, из которого объект, имя класса и шестнадцатеричное представление его расположения в памяти - например:
<__main__.Foo object at 0x7f80665abdd0>
Эта информация не очень полезна, но нет способа определить, как можно точно создать каноническое представление любого данного экземпляра, и это лучше, чем ничего, по крайней мере, сказать нам, как мы можем уникально идентифицировать ее в памяти.
Как может __repr__
быть полезным?
Давайте посмотрим, насколько это может быть полезно, используя оболочку Python и datetime
объекты. Для начала нам нужно импортировать модуль datetime
:
import datetime
Если мы вызовем datetime.now
в оболочке, мы увидим все, что нам нужно, чтобы воссоздать эквивалентный объект даты-времени. Это создается datetime __repr__
:
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
Если мы печатаем объект datetime, мы видим хороший читабельный (на самом деле, ISO) формат. Это реализовано в datetime's __str__
:
>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951
Очень просто воссоздать потерянный объект, потому что мы не присвоили его переменной, скопировав и вставив из вывода __repr__
, а затем напечатав его, и мы получим его в том же читаемом человеком виде как другой объект:
>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180
Как мне их реализовать?
По мере разработки вы захотите воспроизводить объекты в том же состоянии, если это возможно. Так, например, объект datetime определяет __repr__
( Python source ). Это довольно сложно из-за всех атрибутов, необходимых для воспроизведения такого объекта:
def __repr__(self):
"""Convert to formal string, for repr()."""
L = [self._year, self._month, self._day, # These are never zero
self._hour, self._minute, self._second, self._microsecond]
if L[-1] == 0:
del L[-1]
if L[-1] == 0:
del L[-1]
s = "%s.%s(%s)" % (self.__class__.__module__,
self.__class__.__qualname__,
", ".join(map(str, L)))
if self._tzinfo is not None:
assert s[-1:] == ")"
s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
if self._fold:
assert s[-1:] == ")"
s = s[:-1] + ", fold=1)"
return s
Если вы хотите, чтобы ваш объект имел более удобочитаемое представление, вы можете добавить __str__
далее. Вот как объект datetime ( источник Python ) реализует __str__
, что он легко делает, потому что у него уже есть функция для отображения в формате ISO:
def __str__(self):
"Convert to string, for str()."
return self.isoformat(sep=' ')
Набор __repr__ = __str__
?
Это критика другого ответа, который предлагает установить __repr__ = __str__
.
Установка __repr__ = __str__
глупа - __repr__
- это запасной вариант для __str__
, а __repr__
, написанный для разработчиков при отладке, должен быть написан до того, как вы напишите __str__
.
Вам нужен __str__
только тогда, когда вам нужно текстовое представление объекта.
Заключение
Определите __repr__
для объектов, которые вы пишете, чтобы вы и другие разработчики имели воспроизводимый пример при использовании его по мере разработки. Определите __str__
, когда вам нужно его читаемое строковое представление.