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

3120
Casebash 17 Сен 2009 в 08:27

21 ответ

Лучший ответ

Алекс резюмировал хорошо, но, на удивление, был слишком лаконичен.

Прежде всего позвольте мне повторить основные моменты в сообщении Алекса:

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

Это кажется удивительным, не так ли? Это немного, но насколько читабельно было бы, если бы они использовали их __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__, если считаете, что было бы полезно иметь строковую версию с ошибками для удобства чтения.

2659
wjandrea 21 Дек 2019 в 04:05

__repr__ используется везде, кроме методов print и str (когда определено __str__!)

2
techkuz 14 Апр 2019 в 07:50

__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
3
prosti 6 Июн 2019 в 16:53
  1. __str__ должен возвращать строковый объект, тогда как __repr__ может возвращать любое выражение Python.
  2. Если реализация __str__ отсутствует, то функция __repr__ используется в качестве запасного варианта. Если __repr__ реализация функции отсутствует, отступления не будет.
  3. Если функция __repr__ возвращает строковое представление объекта, мы можем пропустить реализацию функции __str__.

Источник: https://www.journaldev.com/22460/python-str- предст -функции

3
Sampath 18 Апр 2019 в 11: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

Надеюсь, что это поможет вам заложить конкретные основания, чтобы найти больше ответов.

3
Calculus 2 Янв 2018 в 10:36
>>> 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 (когда это возможно) воспроизводят представленный объект.

4
Georgy 29 Май 2019 в 12:58

В двух словах:

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'
4
BioGeek 16 Апр 2018 в 09:28

Следует помнить одну важную вещь: контейнер __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__, "формальное" представление объекта. Хотя формальное представление труднее читать, чем неформальное, оно однозначно и более устойчиво к ошибкам.

4
zangw 16 Ноя 2015 в 03:02

Отличные ответы уже охватывают разницу между __str__ и __repr__, которая для меня сводится к тому, что первое читается даже конечным пользователем, а последнее максимально полезно для разработчиков. Учитывая это, я считаю, что реализация по умолчанию __repr__ часто не может достичь этой цели, потому что она пропускает информацию, полезную для разработчиков.

По этой причине, если у меня достаточно простое __str__, я обычно просто пытаюсь получить лучшее из обоих миров с чем-то вроде:

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))
5
cs95 25 Апр 2018 в 19:35

Из книги Свободный Python :

Основным требованием для объекта Python является предоставление пригодного для использования строковые представления самого себя, один используется для отладки и ведение журнала, еще один для представления конечным пользователям. Вот почему
специальные методы __repr__ и __str__ существуют в модели данных.

7
Georgy 29 Май 2019 в 12:57

Один аспект, который отсутствует в других ответах. Это правда, что в целом картина такова:

  • Цель __str__: человекочитаемый
  • Цель __repr__: однозначный, возможно, машиночитаемый через eval

К сожалению, это различие некорректно, потому что Python REPL, а также IPython используют __repr__ для печати объектов в консоли REPL (см. Связанные вопросы для Python и IPython ) . Таким образом, проекты, предназначенные для работы с интерактивной консолью (например, Numpy или Pandas), начали игнорировать вышеприведенные правила и вместо этого предоставляют удобочитаемую __repr__ реализацию.

8
bluenote10 26 Май 2017 в 12:33

str - Создает новый строковый объект из данного объекта.

repr - возвращает каноническое строковое представление объекта.

Различия:

< Сильный > ул ( ) :

  • делает объект читабельным
  • генерирует вывод для конечного пользователя

< Сильный > магнезии ( ) :

  • нужен код, который воспроизводит объект
  • генерирует вывод для разработчика
9
Inconnu 4 Дек 2016 в 16:18

Из (неофициальной) справочной вики-страницы Python (архивная копия) ) от effbot:

__str__ " вычисляет« неформальное »строковое представление объекта. Это отличается от __repr__ тем, что оно не обязательно должно быть допустимым выражением Python: может использоваться более удобное или краткое представление вместо этого. »

12
Georgy 29 Май 2019 в 12:51

Проще говоря:

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

__repr__ используется для отображения строкового представления объекта объекта .

Допустим, я хочу создать класс Fraction, в котором строковое представление дроби равно «(1/2)», а объект (класс дроби) должен быть представлен как «дробь (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)
12
Paulo Freitas 28 Июл 2016 в 04:08

Честно говоря, eval(repr(obj)) никогда не используется. Если вы обнаружите, что используете его, вам следует остановиться, потому что eval опасен, а строки - очень неэффективный способ сериализации ваших объектов (используйте вместо этого pickle).

Поэтому я бы рекомендовал установить __repr__ = __str__. Причина в том, что str(list) вызывает repr для элементов (я считаю, что это один из самых больших недостатков Python в дизайне, который не был исправлен в Python 3). Фактический repr, вероятно, не будет очень полезен как вывод print [your, objects].

Чтобы это уточнить, по моему опыту, наиболее полезный вариант использования функции repr - поместить строку в другую строку (используя форматирование строки). Таким образом, вам не нужно беспокоиться о том, чтобы избежать кавычек или чего-то еще. Но обратите внимание, что здесь eval не происходит.

13
Aaron Hall 14 Апр 2015 в 00:30

Помимо всех ответов, я хотел бы добавить несколько моментов:

1) __repr__() вызывается, когда вы просто пишете имя объекта на интерактивной консоли Python и нажимаете ввод.

2) __str__() вызывается, когда вы используете объект с оператором печати.

3) Если __str__ отсутствует, то print и любая функция, использующая str(), вызывает __repr__() объекта.

4) __str__() контейнеров, при вызове выполнит метод __repr__() его содержащихся элементов.

5) str(), вызываемый внутри __str__(), потенциально может рекурсивно без базового случая и ошибки на максимальной глубине рекурсии.

6) __repr__() может вызвать repr(), который попытается автоматически избежать бесконечной рекурсии, заменив уже представленный объект на ....

28
David Augusto Villa 5 Июн 2018 в 07:47

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

__str__ (читается как «строка dunder (двойное подчеркивание)») и __repr__ (читается как «dunder-repper» (для «представление»)) оба являются специальными методами, которые возвращают строки на основе состояния объекта.

__repr__ обеспечивает режим резервного копирования, если __str__ отсутствует.

Поэтому сначала нужно написать __repr__, который позволяет вам восстановить экземпляр эквивалентного объекта из строки, которую он возвращает, например. используя eval или вводя его символ за символом в оболочке Python.

В любое время позже можно написать __str__ для читаемого пользователем строкового представления экземпляра, когда он считает это необходимым.

__str__

Если вы напечатаете объект или передадите его format, str.format или str, то, если определен метод __str__, этот метод будет вызван, иначе { {X4}} будет использоваться.

__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. Это создается 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__, когда вам нужно его читаемое строковое представление.

111
Maggyero 2 Июн 2019 в 11:35

Короче говоря, цель __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:

repr(object)

Вернуть строку, содержащую печатаемое представление объекта. Это то же самое значение, полученное в результате преобразований (обратный цитаты). Иногда полезно иметь доступ к этой операции как обычная функция. Для многих типов эта функция делает попытку вернуть строку, которая выдаст объект с тем же значением, когда передается eval(), в противном случае представление представляет собой строку, заключенную в угловые скобки, которые содержат название типа объекта вместе с дополнительной информацией, часто включая имя и адрес объекта. Класс может контролировать, что возвращает эта функция для его экземпляров путем определения метода __repr__().

Вот документация для ул:

str(object='')

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

147
deadly 28 Окт 2013 в 00:23

__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
162
Andrew Clark 15 Авг 2012 в 19:40

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

>>> 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__!

389
Alex Martelli 17 Сен 2009 в 04:49

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

496
Ned Batchelder 17 Сен 2009 в 11:35