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


Ответы:


2728

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

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

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


155
Определенно не согласен с вашим мнением, что отладка - это не тот путь. Для разработки используйте отладчик (и / или ведение журнала), для производства используйте ведение журнала. С помощью отладчика вы видите все, что пошло не так, когда возникла проблема. Вы можете увидеть полную картину. Если вы не регистрируетесь ВСЕ, вы не можете получить это. Кроме того, если вы регистрируете все, что вам нужно, вы должны просмотреть тонны данных, чтобы получить то, что вы хотите.
Самуил

21
Отличный ответ (кроме того, что мы не используем отладчики). Я просто хотел бы добавить ссылку на этот другой вопрос-ответ о str vs unicode в Python 3, который мог бы иметь отношение к обсуждению для людей, которые сделали переход.
ThatAintWorking

11
Плюс1 для отладчиков бесполезен и не стоит ни копейки. Вместо этого увеличьте пропускную способность логирования. И да, это был хорошо написанный пост. Оказалось, это __repr__было то, что мне нужно для отладки. Спасибо за помощь.
personal_cloud

7
Отвлекись от твоего отладчика, я узнал% r, и это все равно стоит голоса
Микки Перлштейн

7
на отладчике против отладчика: не получите таких укоренившихся мнений. В некоторых приложениях отладка нереалистична, как правило, когда используется реальное время, или когда ваш код выполняется только удаленно на платформе с небольшим доступом или без консоли. В большинстве других случаев гораздо быстрее будет остановиться на исключении для расследования или установить точку останова, потому что вам не нужно проходить тысячи строк журналирования (что будет загромождать ваш диск и замедлять работу приложения). Наконец, не всегда возможно войти в систему, например, на встроенных устройствах, там отладчик тоже ваш друг.
RedGlyph

523

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


2
Это верно, потому что для obj = uuid.uuid1 () obj .__ str __ () равен "2d7fc7f0-7706-11e9-94ae-0242ac110002", а obj .__ repr __ () равен "UUID ('2d7fc7f0-7706-11e9-94ae-0242-0242) «)». Разработчикам нужна (ценность + происхождение), тогда как клиентам нужна ценность, и им все равно, как они ее получили!
Нарен Йеллавула

1
Здесь клиент не обязательно означает конечного пользователя. Это клиент или пользователь объекта. Так что если это SDK, то разработчики SDK будут использовать __str__так, чтобы у обычных разработчиков был читаемый объект. С другой стороны, __repr__для самих разработчиков SDK.
Шиплу Мокаддим

398

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

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


34
В моих модульных тестах я всегда проверяю, eval(repr(foo))оценивается ли объект как равный foo. Вы правы, что он не будет работать вне моих тестовых случаев, так как я не знаю, как импортируется модуль, но это по крайней мере гарантирует, что он работает в некотором предсказуемом контексте. Я думаю, что это хороший способ оценки, если результат __repr__достаточно явный. Выполнение этого в модульном тесте также помогает обеспечить __repr__последующие изменения в классе.
Стивен Т. Снайдер

4
Я всегда стараюсь убедиться, что либо 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__вместо этого более уродливый объект .
SuperGeo

Просто наткнулся на досадную ошибку, связанную с тем, что она eval(repr(x))не работает даже для встроенных типов: class A(str, Enum): X = 'x'будет вызывать SyntaxError eval(repr(A.X)). Это грустно, но понятно. Кстати, на eval(str(A.X))самом деле работает, но, конечно, только если class Aнаходится в области видимости - так что, вероятно, это не очень полезно.
максимум

@SuperGeo Другие ответы охватывают это: strэлемент использования контейнера, reprпотому что [1, 2, 3]! = ["1", "2, 3"].
mtraceur

163

__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

151

Короче говоря, цель __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(); его цель - вернуть строку для печати. Если аргумент не указан, возвращает пустую строку ''.


1
В чем смысл печатной строки здесь? Можете ли вы объяснить это, пожалуйста?
Vicrobot

115

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

__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(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__быть полезно?

Давайте посмотрим, насколько это может быть полезно, используя оболочку и datetimeобъекты Python . Сначала нам нужно импортировать 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__и a __repr__, написанный для разработчиков при отладке, должен быть написан до того, как вы напишите a __str__.

Вам нужно __str__только тогда, когда вам нужно текстовое представление объекта.

Вывод

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


Разве это не должно быть чем-то вроде type(obj).__qualname__?
Соломон Уко

@SolomonUcko да, в Python 3 это могло бы быть так - я искал исходный код, где это реализовано, и я дополню свой ответ этой информацией, когда соберу его.
Аарон Холл

33

На странице 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'

Это на стр. # 351.
Jiten

4
Это вводит в заблуждение, чтобы называть reprвоспроизводить. Лучше думать об этом как о представлении.
НельсонГон

31

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

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

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

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

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

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

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


14

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

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

13

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

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

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


19
Я думаю, что это упускает из виду. Использование eval(repr(obj))- это проверка работоспособности и практическое правило - если это правильно воссоздает исходный объект, то у вас есть достойная __repr__реализация. Это не означает, что вы действительно сериализуете объекты таким образом.
JWG

7
evalне является опасным по своей природе. Не более опасно , чем unlink, openили записи файлов. Должны ли мы прекратить запись в файлы, потому что, возможно, злонамеренная атака может использовать произвольный путь к файлу для помещения содержимого внутрь? Все опасно, если тупо используется немыми людьми. Идиотизм опасен. Эффекты Даннинг-Крюгера опасны. evalэто просто функция.
Луис Масуэлли

12

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

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


3
__repr__ни в коем случае не требуется возвращать пустое выражение Python.
Безумный физик

10

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

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

Различия:

ул ():

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

магнезии ():

  • нужен код, который воспроизводит объект
  • генерирует вывод для разработчика

8

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

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

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


7

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

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


5

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

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

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))

4

Важно помнить, что контейнер __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__) не определено! Итак, вы не правы.
Jiten

4

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

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

__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

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

Источник: https://www.journaldev.com/22460/python-str-repr-functions


2

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.