В чем разница между __str__
и __repr__
в Python?
источник
В чем разница между __str__
и __repr__
в Python?
Алекс подвела итог, но, на удивление, была слишком лаконична.
Во-первых, позвольте мне повторить основные моменты в посте Алекса :
__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)
Но вы должны сделать последний шаг - убедиться, что у каждого объекта, который вы реализуете, есть полезный 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__
Это кажется удивительным, не так ли? Это немного, но насколько читабельно было бы, если бы они использовали их __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__
было то, что мне нужно для отладки. Спасибо за помощь.Мое эмпирическое правило:
__repr__
для разработчиков,__str__
для клиентов.источник
__str__
так, чтобы у обычных разработчиков был читаемый объект. С другой стороны,__repr__
для самих разработчиков SDK.Если вы специально не будете действовать иначе, большинство классов не получат полезных результатов ни для одного из них:
Как видите - никакой разницы и никакой информации, кроме класса и объекта
id
. Если вы переопределите только один из двух ...:как вы видите, если вы переопределите
__repr__
, это также используется для__str__
, но не наоборот.Другие важные моменты, которые необходимо знать:
__str__
встроенный контейнер использует__repr__
, а НЕ__str__
элементы, которые он содержит. И, несмотря на слова на эту тему, которые можно найти в типичных документах, вряд ли кто-то потрудится сделать__repr__
из объектов строку, которуюeval
можно использовать для создания равного объекта (это слишком сложно, И незнание того, как на самом деле был импортирован соответствующий модуль, делает его фактически утончаться невозможно).Итак, мой совет: сосредоточьтесь на том, чтобы сделать
__str__
разумно читаемым и__repr__
настолько недвусмысленным, насколько это возможно, даже если это мешает нечеткой недостижимой цели сделать__repr__
возвращаемое значение приемлемым в качестве входных данных для__eval__
!источник
eval(repr(foo))
оценивается ли объект как равныйfoo
. Вы правы, что он не будет работать вне моих тестовых случаев, так как я не знаю, как импортируется модуль, но это по крайней мере гарантирует, что он работает в некотором предсказуемом контексте. Я думаю, что это хороший способ оценки, если результат__repr__
достаточно явный. Выполнение этого в модульном тесте также помогает обеспечить__repr__
последующие изменения в классе.eval(repr(spam)) == spam
(хотя бы в правильном контексте), либоeval(repr(spam))
поднимаетSyntaxError
. Таким образом вы избежите путаницы. (И это почти верно для встроенных функций и большей части stdlib, за исключением, например, рекурсивных списков, гдеa=[]; a.append(a); print(eval(repr(a)))
вы можете[[Ellipses]]
...) Конечно, я не делаю это для фактического использованияeval(repr(spam))
, за исключением проверки работоспособности в модульных тестах ... но я делать иногда копировать и вставлятьrepr(spam)
в интерактивной сессии.__str__
для каждого элемента__repr__
? Мне кажется, что это неправильно, поскольку я реализовал читаемый__str__
объект в своем объекте, и когда он является частью списка, я вижу__repr__
вместо этого более уродливый объект .eval(repr(x))
не работает даже для встроенных типов:class A(str, Enum): X = 'x'
будет вызывать SyntaxErroreval(repr(A.X))
. Это грустно, но понятно. Кстати, наeval(str(A.X))
самом деле работает, но, конечно, только еслиclass A
находится в области видимости - так что, вероятно, это не очень полезно.str
элемент использования контейнера,repr
потому что[1, 2, 3]
! =["1", "2, 3"]
.__repr__
: представление объекта python обычно eval преобразует его обратно в этот объект__str__
: все, что вы думаете, является этим объектом в текстовой форменапример
источник
Вот хороший пример:
Прочитайте эту документацию для repr:
Вот документация для ул:
источник
__str__
(читается как «строка dunder (двойное подчеркивание)») и__repr__
(читается как «dunder-repper» (для «представления»)) оба являются специальными методами, которые возвращают строки, основанные на состоянии объекта.__repr__
обеспечивает резервное копирование, если__str__
отсутствует.Поэтому сначала нужно написать a,
__repr__
который позволит вам восстановить экземпляр эквивалентного объекта из строки, которую он возвращает, например, используяeval
или вводя его символ за символом в оболочке Python.В любое время позже можно написать
__str__
для читаемого пользователем строкового представления экземпляра, когда он считает это необходимым.__str__
Если вы печатаете объект, или передать его
format
,str.format
илиstr
, то если__str__
метод определен, что метод будет вызван, в противном случае,__repr__
будет использоваться.__repr__
__repr__
Метод вызывается функция встроенаrepr
и то , что находит отражение в вашем питоне оболочке , когда он вычисляет выражение , которое возвращает объект.Поскольку он обеспечивает резервное копирование
__str__
, если вы можете написать только один, начните с__repr__
Вот встроенная справка
repr
:То есть для большинства объектов, если вы напечатаете то, что напечатано
repr
, вы сможете создать эквивалентный объект. Но это не реализация по умолчанию.Реализация по умолчанию
__repr__
Объект по умолчанию
__repr__
( исходный код C Python ) выглядит примерно так:Это означает, что по умолчанию вы будете печатать модуль, из которого объект, имя класса и шестнадцатеричное представление его местоположения в памяти - например:
Эта информация не очень полезна, но нет способа определить, как можно точно создать каноническое представление любого конкретного экземпляра, и это лучше, чем ничего, по крайней мере, сказать нам, как мы можем уникально идентифицировать ее в памяти.
Чем может
__repr__
быть полезно?Давайте посмотрим, насколько это может быть полезно, используя оболочку и
datetime
объекты Python . Сначала нам нужно импортироватьdatetime
модуль:Если мы вызовем
datetime.now
оболочку, мы увидим все, что нам нужно, чтобы воссоздать эквивалентный объект datetime. Это создано datetime__repr__
:Если мы печатаем объект datetime, мы видим хороший читабельный (на самом деле, ISO) формат. Это реализовано с помощью datetime
__str__
:Это простой вопрос - воссоздать потерянный объект, потому что мы не присвоили его переменной, скопировав и вставив из
__repr__
вывода, а затем распечатав его, и мы получим его в том же читаемом человеком виде, что и другой объект:Как мне их реализовать?
По мере разработки вы захотите иметь возможность воспроизводить объекты в том же состоянии, если это возможно. Так, например, определяет объект datetime
__repr__
( источник Python ). Это довольно сложно из-за всех атрибутов, необходимых для воспроизведения такого объекта:Если вы хотите, чтобы ваш объект имел более удобочитаемое представление, вы можете реализовать
__str__
следующее. Вот как реализуется объект datetime ( источник Python )__str__
, что он легко делает, потому что у него уже есть функция для отображения в формате ISO:Установить
__repr__ = __str__
?Это критика другого ответа здесь, который предлагает установку
__repr__ = __str__
.Установка
__repr__ = __str__
глупа -__repr__
это запасной вариант,__str__
и a__repr__
, написанный для разработчиков при отладке, должен быть написан до того, как вы напишите a__str__
.Вам нужно
__str__
только тогда, когда вам нужно текстовое представление объекта.Вывод
Определите
__repr__
для объектов, которые вы пишете, чтобы вы и другие разработчики имели воспроизводимый пример при использовании его в процессе разработки. Определите,__str__
когда вам нужно удобочитаемое представление строки.источник
type(obj).__qualname__
?На странице 358 книги Ханса Петтера Лангтангена «Создание сценариев Python для вычислительной науки » четко сказано, что
__repr__
цели в полном строковом представлении объекта;__str__
Это вернуть хорошую строку для печати.Поэтому я предпочитаю понимать их как
с точки зрения пользователя, хотя это недоразумение, которое я сделал при изучении Python.
Небольшой, но хороший пример также приведен на той же странице:
пример
источник
repr
воспроизводить. Лучше думать об этом как о представлении.Помимо всех ответов, я хотел бы добавить несколько моментов:
1)
__repr__()
вызывается, когда вы просто пишете имя объекта на интерактивной консоли Python и нажимаете ввод.2)
__str__()
вызывается при использовании объекта с оператором печати.3) В случае, если
__str__
отсутствует, то печатать и любую функцию, используяstr()
вызовы__repr__()
объекта.4)
__str__()
из контейнеров, при вызове будет выполнять__repr__()
метод содержащихся в нем элементов.5)
str()
вызов внутри__str__()
мог потенциально рекурсировать без базового случая и ошибки на максимальной глубине рекурсии.6)
__repr__()
может вызвать,repr()
который попытается автоматически избежать бесконечной рекурсии, заменив уже представленный объект на...
.источник
Проще говоря:
__str__
используется, чтобы показать строковое представление вашего объекта, которое будет легко читаться другими.__repr__
используется , чтобы показать строковое представление на объекте.Допустим, я хочу создать
Fraction
класс, в котором строковое представление дроби равно «(1/2)», а объект (класс дроби) должен быть представлен как «дробь (1,2)».Таким образом, мы можем создать простой класс Fraction:
источник
Честно говоря,
eval(repr(obj))
никогда не используется. Если вы обнаружите, что используете его, вам следует остановиться, потому чтоeval
это опасно, а строки - очень неэффективный способ сериализации ваших объектов (используйтеpickle
вместо этого).Поэтому я бы порекомендовал настройку
__repr__ = __str__
. Причина заключается в том, чтоstr(list)
вызовыrepr
на элементах (я считаю , что это один из самых больших недостатков конструкции Питона , который не был адресован на Python 3). Фактическоеrepr
, вероятно, не будет очень полезным, как результатprint [your, objects]
.Чтобы это уточнить, по моему опыту, наиболее полезный вариант использования
repr
функции - поместить строку в другую строку (используя форматирование строки). Таким образом, вам не нужно беспокоиться о том, чтобы избежать кавычек или чего-то еще. Но учтите, что здесь ничего неeval
происходит.источник
eval(repr(obj))
- это проверка работоспособности и практическое правило - если это правильно воссоздает исходный объект, то у вас есть достойная__repr__
реализация. Это не означает, что вы действительно сериализуете объекты таким образом.eval
не является опасным по своей природе. Не более опасно , чемunlink
,open
или записи файлов. Должны ли мы прекратить запись в файлы, потому что, возможно, злонамеренная атака может использовать произвольный путь к файлу для помещения содержимого внутрь? Все опасно, если тупо используется немыми людьми. Идиотизм опасен. Эффекты Даннинг-Крюгера опасны.eval
это просто функция.Из (неофициальной) справочной вики по Python (архивная копия) от effbot:
__str__
« вычисляет« неформальное »строковое представление объекта. Это отличается от того,__repr__
что оно не обязательно должно быть допустимым выражением Python: вместо него можно использовать более удобное или краткое представление ».источник
__repr__
ни в коем случае не требуется возвращать пустое выражение Python.str
- Создает новый строковый объект из данного объекта.repr
- Возвращает каноническое строковое представление объекта.Различия:
ул ():
магнезии ():
источник
Один аспект, который отсутствует в других ответах. Это правда, что в целом картина такова:
__str__
: человекочитаемый__repr__
: однозначное, возможно машиночитаемое черезeval
К сожалению, это различие некорректно, поскольку Python REPL, а также IPython используют
__repr__
для печати объектов в консоли REPL (см. Связанные вопросы по Python и IPython ). Таким образом, проекты, предназначенные для работы с интерактивной консолью (например, Numpy или Pandas), начали игнорировать вышеприведенные правила и__repr__
вместо этого предоставляют удобочитаемую реализацию.источник
Из книги Свободный Питон :
источник
Отличные ответы уже охватывают разницу между
__str__
и__repr__
, которая для меня сводится к тому, что первое читается даже конечным пользователем, а второе максимально полезно для разработчиков. Учитывая это, я считаю, что реализация по умолчанию__repr__
часто не может достичь этой цели, потому что в ней отсутствует информация, полезная для разработчиков.По этой причине, если у меня все достаточно просто
__str__
, я, как правило, просто пытаюсь получить лучшее из обоих миров с чем-то вроде:источник
Python предпочитает однозначность читаемости ,
__str__
вызовыtuple
вызовов содержащихся объектов__repr__
, «формальное» представление объекта. Хотя формальное представление труднее читать, чем неформальное, оно однозначно и более устойчиво к ошибкам.источник
__repr__
когда оно (__str__
) не определено! Итак, вы не правы.В двух словах:
источник
Когда
print()
вызывается результат,decimal.Decimal(23) / decimal.Decimal("1.05")
выводится необработанное число; этот вывод в виде строки, который может быть достигнут с__str__()
. Если мы просто введем выражение, мы получимdecimal.Decimal
вывод - этот вывод представлен в виде представления, который может быть достигнут с помощью__repr__()
. Все объекты Python имеют две выходные формы. Строковая форма предназначена для чтения человеком. Представительная форма предназначена для создания выходных данных, которые при передаче интерпретатору Python (когда это возможно) воспроизводят представленный объект.источник
__str__
может быть вызван для объекта путем вызоваstr(obj)
и должен вернуть читаемую человеком строку.__repr__
может быть вызван для объекта путем вызоваrepr(obj)
и должен возвращать внутренний объект (поля / атрибуты объекта)Этот пример может помочь:
источник
Понять
__str__
и__repr__
интуитивно и постоянно различать их вообще.__str__
вернуть замаскированное тело строки данного объекта для читабельности глаз;__repr__
вернуть реальное тело тела данного объекта (вернуть себя) для однозначности идентификации.Смотрите это в примере
Относительно
__repr__
Мы можем сделать арифметическую операцию по
__repr__
результатам удобно.если применить операцию на
__str__
Возвращает только ошибку.
Другой пример.
Надеюсь, что это поможет вам заложить конкретные основания, чтобы найти больше ответов.
источник
__str__
должен возвращать строковый объект, тогда как__repr__
может возвращать любое выражение Python.__str__
реализация отсутствует,__repr__
функция используется как запасной вариант. Нет возврата, если__repr__
реализация функции отсутствует.__repr__
функция возвращает строковое представление объекта, мы можем пропустить реализацию__str__
функции.Источник: https://www.journaldev.com/22460/python-str-repr-functions
источник
__repr__
используется повсеместно, за исключениемprint
иstr
методы (когда__str__
определяется!)источник