Разница между __str__и __repr__.

python magic-methods repr


В чем разница между __str__ и __repr__ в Python?




Answer 1 moshez


Алекс подвела итог, но, на удивление, была слишком лаконична.

Во-первых, позвольте мне повторить основные моменты в посте Алекса :

  • Реализация по умолчанию бесполезна (трудно придумать, чего бы не было, но да)
  • __repr__ цель - быть однозначным
  • __str__ цель - быть читабельным
  • Контейнер __str__ использует __repr__ объекты __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__ объекты __repr__

Это кажется удивительным, не так ли? Это немного, но насколько читабельно было бы, если бы он использовал их __str__ ?

[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]

Не очень. В частности, строки в контейнере слишком легко нарушить его представление строки. Помните, что перед лицом двусмысленности Python сопротивляется искушению угадать. Если вам нужно описанное выше поведение при печати списка, просто

print "[" + ", ".join(l) + "]"

(Вы также можете выяснить, что делать со словарями.

Summary

Реализовать __repr__ для любого класса вы реализуете. Это должно быть вторая натура. Реализовать __str__ , если вы думаете , что было бы полезно иметь версию строки , которая грешит на стороне читаемости.




Answer 2 Ned Batchelder


Мое эмпирическое правило: __repr__ для разработчиков, __str__ для клиентов.




Answer 3 Alex Martelli


Если вы специально не действуете для того,чтобы гарантировать обратное,большинство классов не имеют полезных результатов ни для того,ни для другого:

>>> 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__ превращением __repr__ объектов в строку, которую eval может использовать для создания равного объекта (это слишком сложно, и незнание того, как на самом деле был импортирован соответствующий модуль, делает это фактически утончается невозможно).

Итак, мой совет: акцент на создании __str__ достаточно для восприятия человеком, и __repr__ столь однозначна , как вы , возможно , может, даже если что мешает нечеткой недостижимой цели создания __repr__ «ы возвращаемое значение приемлемым в качестве вклада в __eval__ !




Answer 4 Andrew Clark


__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



Answer 5 bitoffdev


Короче говоря, цель __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(object='')

Вернуть строку, содержащую хорошо печатаемое представление объекта. Для строк это возвращает саму строку. Разница с repr(object) состоит в том, что str(object) не всегда пытается вернуть строку, приемлемую для eval() ; его цель - вернуть строку для печати. Если аргумент не указан, возвращает пустую строку '' .