Разница между __str__ и __repr__?
В чем разница между __str__
и __repr__
в Python?
Ответы
Ответ 1
Алекс подвела итог, но, на удивление, была слишком лаконична.
Во-первых, позвольте мне повторить основные моменты в посте Алекса:
- Реализация по умолчанию бесполезна (сложно придумать, чего бы не было, но да)
-
__repr__
цель состоит в том, чтобы быть однозначным -
__str__
цель - быть читабельным - Контейнеры
__str__
использует содержащиеся объекты __repr__
Реализация по умолчанию бесполезна
Это в основном сюрприз, потому что значения Python по умолчанию довольно полезны. Тем не менее, в этом случае наличие по умолчанию для __repr__
которое будет действовать следующим образом:
return "%s(%r)" % (self.__class__, self.__dict__)
было бы слишком опасно (например, слишком легко попасть в бесконечную рекурсию, если объекты ссылаются друг на друга). Так что Python справляется. Обратите внимание, что существует одно значение по умолчанию: true, если __repr__
определен, а __str__
нет, объект будет вести себя так, как если бы __str__=__repr__
.
Проще говоря, это означает, что почти каждый реализуемый вами объект должен иметь функционал __repr__
можно использовать для понимания объекта. Реализация __str__
необязательна: делайте это, если вам нужна функциональность "симпатичная печать" (например, используемая генератором отчетов).
Цель __repr__
- быть однозначным
Позвольте мне выйти и сказать это - я не верю в отладчики. Я действительно не знаю, как использовать любой отладчик, и никогда не использовал его серьезно. Кроме того, я считаю, что большая ошибка отладчиков заключается в их основной природе - большинство ошибок, которые я отлаживал, произошли очень давно, в галактике очень далеко. Это означает, что я с религиозным рвением верю в заготовку леса. Ведение журналов - жизненная основа любой достойной серверной системы, работающей по принципу "забей и забудь". Python облегчает вход в систему: возможно, с некоторыми обертками, специфичными для проекта, все, что вам нужно, это
log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c)
Но вы должны сделать последний шаг - убедиться, что у каждого объекта, который вы реализуете, есть полезный repr, чтобы подобный код мог просто работать. Вот почему возникает "eval": если у вас достаточно информации, eval(repr(c))==c
, это означает, что вы знаете все, что нужно знать о c
. Если это достаточно просто, по крайней мере, нечетко, сделайте это. Если нет, убедитесь, что у вас достаточно информации о c
. Я обычно использую eval-подобный формат: "MyClass(this=%r,that=%r)" % (self.this,self.that)
. Это не означает, что вы на самом деле можете создать MyClass или что это правильные аргументы конструктора - но это полезная форма для выражения "это все, что вам нужно знать об этом экземпляре".
Примечание: я использовал %r
выше, а не %s
. Вы всегда хотите использовать repr()
[или символ форматирования %r
, эквивалентно] внутри реализации __repr__
, или вы побеждаете цель repr. Вы хотите иметь возможность различать MyClass(3)
и MyClass("3")
.
Цель __str__
- быть читабельным
В частности, оно не должно быть однозначным - обратите внимание, что str(3)==str("3")
. Точно так же, если вы реализуете абстракцию IP, иметь такую строку, как 192.168.1.1, просто прекрасно. При реализации абстракции даты/времени str может быть "2010/4/12 15:35:22" и т.д. Цель состоит в том, чтобы представить ее так, чтобы ее захотел прочитать пользователь, а не программист. Отрежьте ненужные цифры, притворитесь каким-то другим классом - пока он поддерживает читабельность, это улучшение.
Контейнеры __str__
использует содержащиеся объекты __repr__
Это кажется удивительным, не так ли? Это немного, но насколько бы читабельным было бы
[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]
быть? Не очень. В частности, строки в контейнере слишком легко нарушить его представление строки. Помните, что перед лицом двусмысленности Python сопротивляется искушению угадать. Если вам нужно описанное выше поведение при печати списка, просто
print "[" + ", ".join(l) + "]"
(Вы также можете выяснить, что делать со словарями.
Резюме
__repr__
для любого класса, который вы реализуете. Это должно быть вторая натура. __str__
если вы считаете, что было бы полезно иметь строковую версию с ошибками для удобства чтения.
Ответ 2
Мое правило: __repr__
для разработчиков, __str__
для клиентов.
Ответ 3
Если вы специально не обязываетесь в противном случае, большинство классов не имеют полезных результатов для:
>>> class Sic(object): pass
...
>>> print str(Sic())
<__main__.Sic object at 0x8b7d0>
>>> print repr(Sic())
<__main__.Sic object at 0x8b7d0>
>>>
Как вы видите - никакой разницы и никакой информации, кроме класса и объекта id
. Если вы только переопределите один из двух...:
>>> class Sic(object):
... def __repr__(object): return 'foo'
...
>>> print str(Sic())
foo
>>> print repr(Sic())
foo
>>> class Sic(object):
... def __str__(object): return 'foo'
...
>>> print str(Sic())
foo
>>> print repr(Sic())
<__main__.Sic object at 0x2617f0>
>>>
как вы видите, если вы переопределите __repr__
, который ТАКЖЕ используется для __str__
, но не наоборот.
Другие важные моменты: __str__
на встроенном контейнере использует __repr__
, а не __str__
для элементов, которые он содержит. И, несмотря на слова по этому вопросу, найденные в типичных документах, вряд ли кто-нибудь беспокоится о том, что __repr__
объектов будет строкой, которую eval
может использовать для создания равного объекта (это слишком сложно, И не зная, как соответствующий модуль был фактически импортирован, делает его фактически плоским невозможным).
Итак, мой совет: сосредоточьтесь на том, чтобы сделать __str__
разумно понятным для человека и __repr__
настолько однозначным, насколько возможно, даже если это мешает нечеткой недостижимой цели сделать возвращаемое значение __repr__
приемлемым в качестве входного __eval__
!
Ответ 4
__repr__
: представление объекта python обычно eval будет преобразовывать его обратно в этот объект
__str__
: это то, что вы думаете, это объект в текстовой форме
например.
>>> s="""w'o"w"""
>>> repr(s)
'\'w\\\'o"w\''
>>> str(s)
'w\'o"w'
>>> eval(str(s))==s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
w'o"w
^
SyntaxError: EOL while scanning single-quoted string
>>> eval(repr(s))==s
True
Ответ 5
Короче говоря, цель __repr__
- быть однозначной, а __str__
- читаемым.
Вот хороший пример:
>>> import datetime
>>> today = datetime.datetime.now()
>>> str(today)
'2012-03-14 09:21:58.130922'
>>> repr(today)
'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'
Прочтите эту документацию для версии:
repr(object)
Возвращает строку, содержащую печатаемое представление объекта. Это то же значение, которое дает конверсия (обратная кавычки). Иногда полезно иметь доступ к этой операции как обычная функция. Для многих типов эта функция делает попытку для возврата строки, которая даст объект с тем же значением, когда передан в eval()
, иначе представление представляет собой строку, заключенную в угловые скобки, содержащие имя типа объекта вместе с дополнительной информацией, часто включающей название и адрес объекта. Класс может управлять тем, что возвращает эта функция для его экземпляров, определяя метод __repr__()
.
Вот документация для str:
str(object='')
Возвращает строку, содержащую красиво представление объекта. Для строк это возвращает строку сам. Разница с repr(object)
заключается в том, что str(object)
не всегда пытайтесь вернуть строку, приемлемую для eval()
; его Цель состоит в том, чтобы вернуть печатную строку. Если аргумент не указан, возвращается пустая строка, ''
.
Ответ 6
В чем разница между __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) __repr__
примерно так:
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. Это создается datetime __repr__
:
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
Если мы печатаем объект datetime, мы видим хороший читабельный (на самом деле, ISO) формат. Это реализовано datetime __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). Это довольно сложно из-за всех атрибутов, необходимых для воспроизведения такого объекта:
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__
next. Вот как объект datetime (источник Python) реализует __str__
, что он легко делает, потому что у него уже есть функция для отображения в формате ISO:
def __str__(self):
"Convert to string, for str()."
return self.isoformat(sep=' ')
Установить __repr__ = __str__
?
Это критика другого ответа, который предлагает установить __repr__ = __str__
.
Установка __repr__ = __str__
глупа - __repr__
является __repr__
для __str__
а __repr__
, написанный для разработчиков при отладке, должен быть написан до того, как вы напишите __str__
.
__str__
вам нужен только тогда, когда вам нужно текстовое представление объекта.
Заключение
Определите __repr__
для объектов, которые вы пишете, чтобы вы и другие разработчики имели воспроизводимый пример при использовании его по мере разработки. Определите __str__
когда вам нужно его читаемое строковое представление.
Ответ 7
Помимо всех ответов, я хотел бы добавить несколько моментов:
1) __repr__()
вызывается, когда вы просто пишете имя объекта на интерактивной консоли python и нажимаете ввод.
2) __str__()
вызывается, когда вы используете объект с оператором печати.
3) В случае если __str__
отсутствует, то print и любая функция, использующая str()
вызывает __repr__()
объекта.
4) __str__()
контейнеров, при вызове выполнит __repr__()
его содержащихся элементов.
5) str()
вызываемая в __str__()
потенциально может рекурсировать без базового случая и ошибки при максимальной глубине рекурсии.
6) __repr__()
может вызвать repr()
который попытается автоматически избежать бесконечной рекурсии, заменив уже представленный объект на ...
Ответ 8
На странице 358 книги Ханса Петтера Лангтангена "Создание сценариев Python для вычислительной науки " четко сказано, что
-
__repr__
стремится к полному строковому представлению объекта; -
__str__
возвращает хорошую строку для печати.
Поэтому я предпочитаю понимать их как
- repr = воспроизводить
- str = строка (представление)
с точки зрения пользователя, хотя это недоразумение, которое я сделал при изучении Python.
Небольшой, но хороший пример также приведен на той же странице:
пример
In [38]: str('s')
Out[38]: 's'
In [39]: repr('s')
Out[39]: "'s'"
In [40]: eval(str('s'))
Traceback (most recent call last):
File "<ipython-input-40-abd46c0c43e7>", line 1, in <module>
eval(str('s'))
File "<string>", line 1, in <module>
NameError: name 's' is not defined
In [41]: eval(repr('s'))
Out[41]: 's'
Ответ 9
Всем честно, eval(repr(obj))
никогда не используется. Если вы его используете, вы должны остановиться, потому что eval
является опасным, а строки - очень неэффективным способом сериализации ваших объектов (вместо этого используйте pickle
).
Поэтому я бы рекомендовал установить __repr__ = __str__
. Причина в том, что str(list)
вызывает repr
для элементов (я считаю, что это один из самых больших недостатков дизайна Python, который не рассматривался Python 3). Фактический repr
, вероятно, не будет очень полезен для вывода print [your, objects]
.
Чтобы квалифицировать это, по моему опыту, наиболее полезным вариантом использования функции repr
является поместить строку внутри другой строки (используя форматирование строк). Таким образом, вам не нужно беспокоиться об ускорении кавычек или чего-то еще. Но обратите внимание, что здесь нет eval
.
Ответ 10
Проще говоря:
__str__
используется для отображения строкового представления вашего объекта , который легко читается другими.
__repr__
используется для отображения строкового представления объекта .
Предположим, что я хочу создать класс Fraction
, где строковое представление фракции равно "(1/2)", а объект (класс фракции) должен быть представлен как "Фракция (1,2)"
Итак, мы можем создать простой класс фракции:
class Fraction:
def __init__(self, num, den):
self.__num = num
self.__den = den
def __str__(self):
return '(' + str(self.__num) + '/' + str(self.__den) + ')'
def __repr__(self):
return 'Fraction (' + str(self.__num) + ',' + str(self.__den) + ')'
f = Fraction(1,2)
print('I want to represent the Fraction STRING as ' + str(f)) # (1/2)
print('I want to represent the Fraction OBJECT as ', repr(f)) # Fraction (1,2)
Ответ 11
Из (неофициальной) справочной вики Python (архивная копия) от effbot:
__str__
"вычисляет" неформальное "строковое представление объекта. Это отличается от __repr__
в том, что оно не обязательно должно быть допустимым выражением Python: вместо него можно использовать более удобное или сжатое представление."
Ответ 12
Один аспект, отсутствующий в других ответах. Это правда, что в общем случае шаблон выглядит следующим образом:
- Цель
__str__
: доступная для человека
- Цель
__repr__
: однозначная, возможно машиночитаемая через eval
К сожалению, эта дифференциация ошибочна, потому что Python REPL, а также IPython используют __repr__
для печати объектов в консоли REPL (см. связанные вопросы для Python и IPython). Таким образом, проекты, предназначенные для интерактивной работы в консоли (например, Numpy или Pandas), начали игнорировать вышеприведенные правила и вместо этого представлять собой понятную для человека реализацию __repr__
.
Ответ 13
str
- Создает новый строковый объект из данного объекта.
repr
- Возвращает каноническое строковое представление объекта.
Различия:
ул():
- делает объект доступным для чтения
- генерирует выходные данные для конечного пользователя
магнезии():
- требуется код, который воспроизводит объект
- генерирует выходные данные для разработчика
Ответ 14
Отличные ответы уже охватывают разницу между __str__
и __repr__
, которая для меня сводится к тому, что первая читается даже конечным пользователем, а последняя является как можно более полезной для разработчиков. Учитывая это, я нахожу, что реализация __repr__
по умолчанию часто не достигает этой цели, поскольку она не дает информации, полезной для разработчиков.
По этой причине, если у меня достаточно простой __str__
, я обычно пытаюсь получить лучшее из обоих миров с чем-то вроде:
def __repr__(self):
return '{0} ({1})'.format(object.__repr__(self), str(self))
Ответ 15
Из книги Свободный Питон:
Основным требованием к объекту Python является предоставление пригодных для использования строковых представлений, одно из которых используется для отладки и ведения журнала, другое - для представления конечным пользователям. Вот почему
в модели данных существуют специальные методы __repr__
и __str__
.
Ответ 16
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')
Когда print()
вызывается по результату decimal.Decimal(23)/decimal.Decimal("1.05")
печатается необработанное число; это вывод в виде строки, который может быть достигнут с __str__()
. Если мы просто введем выражение, мы получим decimal.Decimal
вывод. decimal.Decimal
вывод - этот вывод представлен в форме представления, которая может быть достигнута с помощью __repr__()
. Все объекты Python имеют две выходные формы. Строковая форма разработана для восприятия человеком. Представительная форма предназначена для создания выходных данных, которые при передаче интерпретатору Python (когда это возможно) воспроизводят представленный объект.
Ответ 17
Важно помнить, что контейнер __str__
использует содержащиеся объекты __repr__
.
>>> from datetime import datetime
>>> from decimal import Decimal
>>> print (Decimal('52'), datetime.now())
(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 51, 26, 185000))
>>> str((Decimal('52'), datetime.now()))
"(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 52, 22, 176000))"
Python поддерживает однозначность над читабельностью, вызов __str__
tuple
вызывает содержащиеся в нем объекты __repr__
, "формальное" представление объекта. Хотя формальное представление труднее читать, чем неофициальное, оно однозначно и более устойчиво к ошибкам.
Ответ 18
В двух словах:
class Demo:
def __repr__(self):
return 'repr'
def __str__(self):
return 'str'
demo = Demo()
print(demo) # use __str__, output 'str' to stdout
s = str(demo) # __str__ is used, return 'str'
r = repr(demo) # __repr__ is used, return 'repr'
import logging
logger = logging.getLogger(logging.INFO)
logger.info(demo) # use __str__, output 'str' to stdout
from pprint import pprint, pformat
pprint(demo) # use __repr__, output 'repr' to stdout
result = pformat(demo) # use __repr__, result is string which value is 'str'
Ответ 19
Чем яснее
из блог
str похож на toString., чтобы вы могли распечатать данные
repr похож на сериализацию или рассол. Как мне воссоздать этот объект, если мне нужно это сделать, используя eval()
>>> import datetime
>>> now = datetime.datetime.now()
>>> str(now)
'2015-04-04 20:51:31.766862'
>>> repr(now)
'datetime.datetime(2015, 4, 4, 20, 51, 31, 766862)'
>>mydate = eval(repr(now))
Ответ 20
Понимать __str__
и __repr__
интуитивно и постоянно различать их вообще.
__str__
возвращает строку замаскированного тела данного объекта для чтения глаз
__repr__
вернуть реальное тело тела данного объекта (вернуть себя) для однозначности, чтобы идентифицировать.
См. это в примере
In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form
Что касается __repr__
In [32]: datetime.datetime.now()
Out[32]: datetime.datetime(2017, 12, 7, 15, 43, 27, 297769)
Presence in real body which allows to be manipulated directly.
Мы можем легко выполнить арифметическую операцию на __repr__
.
In [33]: datetime.datetime.now()
Out[33]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521)
In [34]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) - datetime.datetime(2
...: 017, 12, 7, 15, 43, 27, 297769)
Out[34]: datetime.timedelta(0, 222, 443752)
если применить операцию на __str__
In [35]: '2017-12-07 15:43:14.002752' - '2017-12-07 15:41:14.002752'
TypeError: unsupported operand type(s) for -: 'str' and 'str'
Возвращает только ошибку.
Другой пример.
In [36]: str('string_body')
Out[36]: 'string_body' # in string form
In [37]: repr('real_body')
Out[37]: "'real_body'" #its real body hide inside
Надеюсь, что это поможет вам создать конкретные основания для изучения большего количества ответов.
Ответ 21
__repr__
используется везде, кроме методов print
и str
(когда определен __str__
!)
Ответ 22
-
__str__
должен возвращать строковый объект, тогда как __repr__
может возвращать любое выражение python. - Если реализация
__str__
отсутствует, то функция __repr__
используется как запасной вариант. Нет __repr__
если __repr__
реализация функции __repr__
. - Если функция
__repr__
возвращает __repr__
представление объекта, мы можем пропустить реализацию функции __str__
.
Источник: https://www.journaldev.com/22460/python-str-repr-functions
Ответ 23
__str__
может быть вызван для объекта путем вызова str(obj)
и должен вернуть читаемую человеком строку.
__repr__
может быть вызван для объекта путем вызова repr(obj)
и должен возвращать внутренний объект (поля/атрибуты объекта)
Этот пример может помочь:
class C1:pass
class C2:
def __str__(self):
return str(f"{self.__class__.__name__} class str ")
class C3:
def __repr__(self):
return str(f"{self.__class__.__name__} class repr")
class C4:
def __str__(self):
return str(f"{self.__class__.__name__} class str ")
def __repr__(self):
return str(f"{self.__class__.__name__} class repr")
ci1 = C1()
ci2 = C2()
ci3 = C3()
ci4 = C4()
print(ci1) #<__main__.C1 object at 0x0000024C44A80C18>
print(str(ci1)) #<__main__.C1 object at 0x0000024C44A80C18>
print(repr(ci1)) #<__main__.C1 object at 0x0000024C44A80C18>
print(ci2) #C2 class str
print(str(ci2)) #C2 class str
print(repr(ci2)) #<__main__.C2 object at 0x0000024C44AE12E8>
print(ci3) #C3 class repr
print(str(ci3)) #C3 class repr
print(repr(ci3)) #C3 class repr
print(ci4) #C4 class str
print(str(ci4)) #C4 class str
print(repr(ci4)) #C4 class repr