В чем разница между __str__
и __repr__
в Python?
В чем разница между __str__ и __repr__?
Ответы (24)
Алекс хорошо резюмировал, но, к удивлению, оказался слишком лаконичным.
Во-первых, позвольте мне повторить основные моменты в сообщении Алекса:
- Реализация по умолчанию бесполезна (трудно придумать, что бы не было, но да)
__repr__
цель - быть недвусмысленной__str__
цель - быть читаемым- Контейнер
__str__
использует содержащиеся объекты__repr__
Реализация по умолчанию бесполезна
Это в основном сюрприз, потому что значения по умолчанию для Python, как правило, довольно полезны. Однако в этом случае наличие значения по умолчанию для __repr__
, которое будет действовать следующим образом:
return "%s(%r)" % (self.__class__, self.__dict__)
было бы слишком опасно (например, слишком легко попасть в бесконечную рекурсию, если объекты ссылаются друг на друга). Итак, Python уходит. Обратите внимание, что есть одно значение по умолчанию, которое истинно: если __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)
Но вам нужно сделать последний шаг - убедиться, что каждый объект, который вы реализуете, имеет полезную реплику, чтобы такой код мог просто работать. Вот почему возникает вопрос «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-абстракцию, то ее str будет выглядеть как 192.168.1.1 - это нормально. При реализации абстракции даты / времени str может иметь вид «2010/4/12 15:35:22» и т. Д. Цель состоит в том, чтобы представить его таким образом, чтобы пользователь, а не программист, захотел бы его прочитать. Отрежьте бесполезные цифры, представьте себя каким-то другим классом - пока он поддерживает читаемость, это улучшение.
Контейнер __str__
использует содержащиеся объекты __repr__
Это кажется удивительным, не правда ли? Немного, но насколько читабельно было бы, если бы использовал их __str__
?
[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]
Не очень. В частности, строкам в контейнере будет слишком легко нарушить их строковое представление. Помните, что перед лицом двусмысленности Python сопротивляется искушению предположить. Если вы хотите, чтобы при печати списка выполнялся описанный выше процесс, просто
print "[" + ", ".join(l) + "]"
(вы, вероятно, также сможете понять, что делать со словарями.
Резюме
Реализуйте __repr__
для любого класса, который вы реализуете. Это должно быть второй натурой. Реализуйте __str__
, если считаете, что было бы полезно иметь строковую версию, которая ошибочна для удобочитаемости.
__repr__
был тем, что мне нужно для отладки. Спасибо за помощь.
- person personal_cloud; 29.09.2017
__repr__
, а не __str__
. print(str([today, today]))
печатает [datetime.datetime(2019, 1, 8, 20, 5, 27, 24162), datetime.datetime(2019, 1, 8, 20, 5, 27, 24162)]
.
- person ilias iliadis; 08.01.2019
eval(repr())
безопасно ли использовать, скажем, модуль API, в котором хранятся пароли пользователей?
- person NelsonGon; 19.06.2019
l
(строчная буква L) будет синтаксической ошибкой в python 4.0;)
- person hans; 10.07.2019
__repr__
встроенных данных, добавив !r
: вы можете заменить "MyClass(this=%r,that=%r)" % (self.this,self.that)
на f"MyClass(this={self.this!r},that={self.that!r})"
. В противном случае спасибо за этот отличный пост!
- person joanis; 12.05.2021
Мое практическое правило: __repr__
для разработчиков, __str__
для клиентов.
__str__
, чтобы у обычных разработчиков был читаемый объект. С другой стороны, __repr__
предназначен для самих разработчиков SDK.
- person Shiplu Mokaddim; 09.01.2020
Если вы специально не позаботитесь об обратном, большинство классов не принесут никаких результатов:
>>> 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__
!
eval(repr(foo))
оценивает объект, равный foo
. Вы правы, что это не будет работать вне моих тестовых примеров, поскольку я не знаю, как модуль импортируется, но это, по крайней мере, гарантирует, что он работает в некотором предсказуемом контексте. Я думаю, что это хороший способ оценить, достаточно ли явен результат __repr__
. Выполнение этого в модульном тесте также помогает убедиться, что __repr__
следует за изменениями в классе.
- person Steven T. Snyder; 15.11.2011
eval(repr(spam)) == spam
(по крайней мере, в правильном контексте), либо eval(repr(spam))
поднимает SyntaxError
. Так вы избежите путаницы. (И это почти верно для встроенных функций и большей части stdlib, за исключением, например, рекурсивных списков, где a=[]; a.append(a); print(eval(repr(a)))
дает вам [[Ellipses]]
…) Конечно, я не делаю этого, чтобы на самом деле использовать eval(repr(spam))
, кроме проверки работоспособности в модульных тестах… но я делаю иногда копирую и вставляю repr(spam)
в интерактивный сеанс.
- person abarnert; 20.09.2014
__str__
для каждого элемента вместо __repr__
? Мне это кажется совершенно неправильным, поскольку я реализовал читаемый __str__
в своем объекте, а когда он является частью списка, вместо этого я вижу более уродливый __repr__
.
- person SuperGeo; 26.01.2018
eval(repr(x))
не работает даже для встроенных типов: class A(str, Enum): X = 'x'
вызовет SyntaxError на eval(repr(A.X))
. Это печально, но понятно. Кстати, eval(str(A.X))
на самом деле работает, но, конечно, только если class A
находится в области видимости - так что это, вероятно, не очень полезно.
- person max; 13.01.2019
str
использует элемент repr
, потому что [1, 2, 3]
! = ["1", "2, 3"]
.
- person mtraceur; 06.12.2019
class Spam
, eval(repr(spam)) == spam
также потребует реализации Spam.__eq__
, верно? По умолчанию object.__eq__
использует is
(docs).
- person djvg; 04.12.2020
__repr__
: представление объекта python обычно eval преобразует его обратно в этот объект
__str__
: это то, что вы считаете этим объектом в текстовой форме.
e.g.
>>> 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
Короче говоря, цель
__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()
; его цель - вернуть печатаемую строку. Если аргумент не указан, возвращает пустую строку''
.
В чем разница между
__str__
и__repr__
в Python?
__str__
(читается как «строка с двойным подчеркиванием») и __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__
является (исходный код Python на C ) что-то вроде:
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__
дальше. Вот как объект 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__
, когда вам нужно его строковое представление в удобочитаемой форме.
type(obj).__qualname__
?
- person Solomon Ucko; 01.12.2018
На странице 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'
repr
воспроизведением - это своего рода заблуждение. Лучше думать об этом как о себе.
- person NelsonGon; 19.06.2019
Помимо всех представленных ответов, я хотел бы добавить несколько моментов: -
1) __repr__()
вызывается, когда вы просто пишете имя объекта в интерактивной консоли python и нажимаете ввод.
2) __str__()
вызывается, когда вы используете объект с оператором печати.
3) В случае, если __str__
отсутствует, то print и любая функция, использующая str()
, вызывает __repr__()
объекта.
4) __str__()
контейнеров, при вызове будет выполнять __repr__()
метод содержащихся в нем элементов.
5) str()
, вызываемый в __str__()
, потенциально может рекурсивно выполняться без базового случая и ошибки максимальной глубины рекурсии.
6) __repr__()
может вызывать repr()
, который автоматически пытается избежать бесконечной рекурсии, заменяя уже представленный объект на ...
.
Проще говоря:
__str__
используется, чтобы показать строковое представление вашего объекта, чтобы его могли легко прочитать другие.
__repr__
используется для отображения строкового представления объекта.
Скажем, я хочу создать класс Fraction
, в котором строковое представление дроби - '(1/2)', а объект (класс Fraction) должен быть представлен как 'Fraction (1,2)'
Итак, мы можем создать простой класс Fraction:
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)
Честно говоря, eval(repr(obj))
никогда не используется. Если вы обнаружите, что используете его, вам следует остановиться, потому что eval
опасно, а строки - очень неэффективный способ сериализации ваших объектов (вместо этого используйте pickle
).
Поэтому я бы рекомендовал установить __repr__ = __str__
. Причина в том, что str(list)
вызывает repr
элементы (я считаю, что это один из самых больших недостатков дизайна Python, который не был исправлен в Python 3). Фактический repr
, вероятно, будет не очень полезен как результат print [your, objects]
.
Чтобы уточнить это, по моему опыту, наиболее полезным вариантом использования функции repr
является помещение строки внутри другой строки (с использованием форматирования строки). Таким образом, вам не нужно беспокоиться об экранировании кавычек или чего-то еще. Но учтите, что здесь не происходит eval
.
eval(repr(obj))
- это проверка работоспособности и практическое правило - если это правильно воссоздает исходный объект, то у вас есть достойная __repr__
реализация. Не предполагается, что вы на самом деле сериализуете объекты таким образом.
- person jwg; 06.06.2014
eval
по своей сути не опасен. Не опаснее unlink
, open
или запись в файлы. Должны ли мы прекратить запись в файлы, потому что, возможно, злонамеренная атака может использовать произвольный путь к файлу для помещения содержимого внутрь? Все опасно, если глупые люди тупо используют. Идиотизм опасен. Эффекты Даннинга-Крюгера опасны. eval
- это просто функция.
- person Luis Masuelli; 01.03.2016
Из (неофициальной) справочной вики по Python (архивная копия ) от effbot:
__str__
"вычисляет" неформальное "строковое представление объекта. Это отличается от __repr__
тем, что оно не обязательно должно быть допустимым выражением Python: вместо этого можно использовать более удобное или краткое представление."
__repr__
ни в коем случае не требуется для возврата действующего выражения Python.
- person Mad Physicist; 20.10.2017
str
- Создает новый строковый объект из данного объекта.
repr
- возвращает каноническое строковое представление объекта.
Различия:
str ():
- делает объект читаемым
- генерирует вывод для конечного пользователя
repr ():
- нужен код, воспроизводящий объект
- генерирует вывод для разработчика
Один аспект, которого не хватает в других ответах. Верно, что в целом закономерность такова:
- Цель
__str__
: удобочитаемость - Цель
__repr__
: однозначно, возможно, машиночитаемое черезeval
К сожалению, это различие некорректно, поскольку Python REPL и IPython используют __repr__
для печати объектов в консоли REPL (см. Связанные вопросы для Python и IPython). Таким образом, проекты, предназначенные для работы с интерактивной консолью (например, Numpy или Pandas), начали игнорировать вышеуказанные правила и вместо этого предоставлять удобочитаемую реализацию __repr__
.
В: В чем разница между __str__()
и __repr__()
?
ДЛИННЫЙ
Этот вопрос существует уже давно, и существует множество ответов, большинство из которых верны (не говоря уже о нескольких легендах сообщества Python [!]). Однако, когда дело доходит до мелочей, этот вопрос аналогичен вопросу о разнице между встроенными функциями str()
и repr()
. Я собираюсь описать различия своими словами (что означает, что я могу свободно заимствовать из Core Python Programming, простите меня).
И str()
, и repr()
выполняют одну и ту же базовую задачу: их цель - вернуть строковое представление объекта Python. вид строкового представления - вот что их отличает.
str()
&__str__()
возвращают печатаемое строковое представление объекта ... что-то удобочитаемое / для использования человекомrepr()
&__repr__()
возвращают строковое представление объекта, который является допустимым объектом Python, который можно передатьeval()
или ввести в оболочку Python без получения ошибки.
Например, давайте присвоим строку x
и int
y
, и просто покажем удобочитаемые строковые версии каждого из них:
>>> x, y = 'foo', 123
>>> str(x), str(y)
('foo', '123')
Можем ли мы взять то, что находится внутри кавычек в обоих случаях, и дословно ввести их в интерпретатор Python? Давайте попробуем:
>>> 123
123
>>> foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
Ясно, что вы можете для int
, но не обязательно для str
. Я могу передать '123'
в eval()
, но для 'foo'
это не работает:
>>> eval('123')
123
>>> eval('foo')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'foo' is not defined
Теперь попробуем repr()
; снова выгрузите то, что в паре кавычек для каждой строки:
>>> repr(x), repr(y)
("'foo'", '123')
>>> 123
123
>>> 'foo'
'foo'
Ух ты, они оба работают? Это потому, что 'foo'
, будучи строковым представлением этой строки для печати, не оценивается, но "'foo'"
может. 123
- это допустимый Python int
, который вызывается str()
или repr()
. Что происходит, когда мы вызываем eval()
с ними?
>>> eval('123')
123
>>> eval("'foo'")
'foo'
Это работает, потому что 123
и 'foo'
являются допустимыми объектами Python. Еще один важный вывод: иногда оба возвращают одно и то же (одно и то же строковое представление), но это не всегда так. (И да, да, я могу создать переменную foo
, где eval()
работает, но дело не в этом.)
Дополнительные сведения об обеих парах
- Иногда
str()
иrepr()
вызываются неявно, что означает, что они вызываются от имени пользователей: когда пользователи выполняютprint
(Py1 / Py2) или вызываютprint()
(Py3 +), даже если пользователи не вызываютstr()
явно, такой вызов выполняется от их имени до отображения объекта. - В оболочке Python (интерактивный интерпретатор), если вы вводите переменную в приглашении
>>>
и нажимаете RETURN, интерпретатор отображает результатыrepr()
, неявно вызванного для этого объекта. - Чтобы соединить
str()
иrepr()
с__str__()
и__repr__()
, имейте в виду, что вызовы встроенных функций, то естьstr(x)
илиrepr(y)
, приводят к вызову соответствующих специальных методов их объектов:x.__str__()
илиy.__repr()__
- Реализуя
__str__()
и__repr__()
для ваших классов Python, вы перегружаете встроенные функции (str()
иrepr()
), позволяя передавать экземпляры ваших классов вstr()
иrepr()
. Когда такие вызовы сделаны, они поворачиваются и вызывают класс '__str__()
и__repr__()
(согласно # 3).
Из книги Свободный Python:
Основное требование к объекту Python - предоставить удобные строковые представления самого себя: одно используется для отладки и ведения журнала, а другое - для представления конечным пользователям. Вот почему в модели данных существуют специальные методы
__repr__
и__str__
.
Отличные ответы уже охватывают разницу между __str__
и __repr__
, которая для меня сводится к тому, что первый может быть прочитан даже конечным пользователем, а второй максимально полезен для разработчиков. Учитывая это, я считаю, что реализация __repr__
по умолчанию часто не достигает этой цели, потому что она пропускает информацию, полезную для разработчиков.
По этой причине, если у меня есть достаточно простой __str__
, я обычно просто пытаюсь получить лучшее из обоих миров с помощью чего-то вроде:
def __repr__(self):
return '{0} ({1})'.format(object.__repr__(self), str(self))
Следует иметь в виду, что контейнер
__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__
вложенных объектов, "формальное" представление объекта. Хотя формальное представление труднее читать, чем неформальное, оно недвусмысленно и более устойчиво к ошибкам.
__repr__
, когда он (__str__
) не определен! Значит, ты ошибаешься.
- person jiten; 21.12.2018
В двух словах:
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'
>>> 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
- этот результат находится в репрезентативной форме, чего можно добиться с помощью __repr__()
. Все объекты Python имеют две формы вывода. Строковая форма разработана таким образом, чтобы она была удобочитаемой. Репрезентативная форма предназначена для создания вывода, который, если его передать интерпретатору Python, будет (когда это возможно) воспроизвести представленный объект.
__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
Понять __str__
и __repr__
интуитивно и навсегда отличить их вообще.
__str__
вернуть строку замаскированного тела данного объекта для чтения глазами __repr__
вернуть реальное тело данного объекта (вернуть себя) для однозначной идентификации.
Посмотреть на примере
In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form
As to __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
Надеюсь, это поможет вам построить конкретную основу для поиска дополнительных ответов.
__str__
должен возвращать строковый объект, тогда как__repr__
может возвращать любое выражение Python.- Если реализация
__str__
отсутствует, функция__repr__
используется как резерв. Если реализация функции__repr__
отсутствует, отката нет. - Если функция
__repr__
возвращает строковое представление объекта, мы можем пропустить реализацию функции__str__
.
Источник: https://www.journaldev.com/22460/python-str-repr-functions
__repr__
используется везде, кроме методов print
и str
(когда __str__
определен!)
Каждый объект наследует __repr__
от базового класса, созданного всеми объектами.
class Person:
pass
p=Person()
если вы вызовете repr(p)
, вы получите это по умолчанию:
<__main__.Person object at 0x7fb2604f03a0>
Но если вы вызовете str(p)
, вы получите тот же результат. это потому, что когда __str__
не существует, Python вызывает __repr__
Реализуем свой __str__
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
def __repr__(self):
print("__repr__ called")
return f"Person(name='{self.name}',age={self.age})"
p=Person("ali",20)
print(p)
и str(p)
вернутся
__repr__ called
Person(name='ali',age=20)
давайте добавим __str__()
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
print('__repr__ called')
return f"Person(name='{self.name}, age=self.age')"
def __str__(self):
print('__str__ called')
return self.name
p=Person("ali",20)
если мы вызовем print(p)
и str (p), он вызовет __str__()
, поэтому он вернет
__str__ called
ali
repr(p)
вернется
repr с именем Person (name = 'ali, age = self.age')
Опустим __repr__
и просто реализуем __str__
.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
print('__str__ called')
return self.name
p=Person('ali',20)
print(p)
будет искать __str__
и вернет:
__str__ called
ali
ПРИМЕЧАНИЕ = если бы у нас были определены __repr__
и __str__
, f'name is {p}'
вызвал бы __str__