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

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


person Casebash    schedule 17.09.2009    source источник


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

person moshez    schedule 13.04.2010
comment
Определенно не согласен с вашим мнением, что отладка - это не лучший вариант. Для разработки используйте отладчик (и / или ведение журнала), для производства используйте ведение журнала. С отладчиком вы можете видеть все, что пошло не так, когда возникла проблема. Вы можете увидеть полную картину. Если вы не регистрируете ВСЕ, вы не сможете этого получить. Кроме того, если вы регистрируете все, что вам нужно, вам придется пролезть через тонны данных, чтобы получить то, что вы хотите. - person Samuel; 21.02.2015
comment
Отличный ответ (за исключением того, что не используют отладчики). Я просто хотел бы добавить ссылку на эти другие вопросы и ответы о str vs < b> unicode в Python 3, который может иметь отношение к обсуждению людей, которые сделали переход. - person ThatAintWorking; 24.03.2015
comment
plus1 для отладчиков бесполезны и не масштабируются ни копейки. Вместо этого увеличьте пропускную способность журналирования. И да, это был хорошо написанный пост. Оказывается, __repr__ был тем, что мне нужно для отладки. Спасибо за помощь. - person personal_cloud; 29.09.2017
comment
не считая вашего глупого отладчика, я выучил% r, и это все равно стоит голоса - person Mickey Perlstein; 13.12.2018
comment
@moshez стоит упомянуть, что контейнеры (списки, dicts) всегда используют __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
comment
eval(repr()) безопасно ли использовать, скажем, модуль API, в котором хранятся пароли пользователей? - person NelsonGon; 19.06.2019
comment
Я слышал, что переменная l (строчная буква L) будет синтаксической ошибкой в ​​python 4.0;) - person hans; 10.07.2019
comment
об отладчике и без отладчика: не получайте таких устоявшихся мнений. В некоторых приложениях отладка нереалистична, обычно когда задействовано в реальном времени или когда ваш код выполняется только удаленно на платформе с ограниченным доступом или без консоли. В большинстве других случаев будет намного быстрее остановиться на исключении для расследования или установить точку останова, потому что вам не нужно проходить тысячи строк журнала (что загромождает ваш диск и замедляет работу приложения). Наконец, не всегда можно вести журнал, например, на встроенных устройствах, там отладчик тоже ваш друг. - person RedGlyph; 02.08.2019
comment
Что касается отладки и ведения журнала, они оба полезны. Если ошибка воспроизводима, отладка упрощается. Если ошибка случайная, необходимо вести журнал. - person Marco Sulla; 15.01.2020
comment
@RedGlyph когда ваш код выполняется только удаленно на платформе - это запах кода. Он неявно не имеет модульных тестов и т. Д. Лучшим примером может быть отладка редких стохастических (недетерминированных) ошибок, ошибок IE, которые трудно воспроизвести. Акцент на проблеме, требующей удаленной платформы, а не кода. - person Philip Couling; 25.03.2020
comment
@PhilipCouling Обязательно прочтите внимательно и используйте правильный словарный запас, прежде чем сокращать ответы и комментарии других. Мы используем запах кода, когда при чтении кода обнаруживается что-то, что требует рефакторинга, поскольку он скрывает потенциальную проблему, которая в дальнейшем может вызвать трудные для поиска ошибки или создать плохую общую структуру. Наличие или отсутствие модульного теста - это тоже не то, что вы можете предположить на этом этапе (и это определенно не подразумевается). Наконец, ваше утверждение о лучшем примере не имеет никаких оснований, я действительно использовал отладчик для решения тех проблем, которые часто не выполнялись при ведении журнала. - person RedGlyph; 06.09.2020
comment
@RedGlyph Мне известно, значение. Код, который может быть выполнен только удаленно, действительно затрудняет тестирование, он подразумевает необходимость в каком-то удаленном ресурсе. Модульное тестирование часто имитирует или заглушает такие ресурсы, что приводит к тому, почему код не может быть выполнен локально. Если код действительно не может подключиться к отладчику, я бы обеспокоился тем, какие ошибки были скрыты в результате плохого тестирования. Я действительно считаю, что истинный код только для удаленного доступа не рекомендуется. Вы говорите, что использовали отладчик для ошибок, которые трудно воспроизвести. Это смелое заявление. - person Philip Couling; 07.09.2020
comment
Я не верю в отладчики. Я действительно не знаю, как использовать какой-либо отладчик - это меня взбесило, напоминает мне старый эпизод в Южном парке, где парень никогда не пробовал наркотики, поэтому он уверен, что они злые. Полагаю, мы все боимся неизвестного. - person kraxor; 08.01.2021
comment
Небольшое обновление для последних версий Python 3: вы можете использовать f-строки и по-прежнему вызывать __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__ для клиентов.

person Ned Batchelder    schedule 17.09.2009
comment
Это верно, потому что для obj = uuid.uuid1 () obj .__ str __ () - это 2d7fc7f0-7706-11e9-94ae-0242ac110002, а obj .__ repr __ () - это UUID ('2d7fc7f0-7706-11e9-94ae-0242ac110002ac110002 Разработчикам нужна (ценность + происхождение), тогда как клиентам нужна ценность, и им все равно, как они ее получили! - person Naren Yellavula; 15.05.2019
comment
Здесь клиент не обязательно означает конечного пользователя. Это клиент или пользователь объекта. Поэтому, если это SDK, разработчики SDK будут использовать __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__!

person Alex Martelli    schedule 17.09.2009
comment
В своих модульных тестах я всегда проверяю, что eval(repr(foo)) оценивает объект, равный foo. Вы правы, что это не будет работать вне моих тестовых примеров, поскольку я не знаю, как модуль импортируется, но это, по крайней мере, гарантирует, что он работает в некотором предсказуемом контексте. Я думаю, что это хороший способ оценить, достаточно ли явен результат __repr__. Выполнение этого в модульном тесте также помогает убедиться, что __repr__ следует за изменениями в классе. - person Steven T. Snyder; 15.11.2011
comment
Я всегда стараюсь убедиться, что либо 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
comment
Почему бы контейнерам (спискам, кортежам) не использовать __str__ для каждого элемента вместо __repr__? Мне это кажется совершенно неправильным, поскольку я реализовал читаемый __str__ в своем объекте, а когда он является частью списка, вместо этого я вижу более уродливый __repr__. - person SuperGeo; 26.01.2018
comment
Просто столкнулся с досадной ошибкой, связанной с тем, что 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
comment
@SuperGeo Другие ответы охватывают это: контейнер str использует элемент repr, потому что [1, 2, 3]! = ["1", "2, 3"]. - person mtraceur; 06.12.2019
comment
@abarnert: для пользовательского 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
person Community    schedule 17.09.2009

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

person bitoffdev    schedule 25.10.2013
comment
Что здесь означает печатаемая строка? Вы можете объяснить это, пожалуйста? - person Vicrobot; 19.08.2018
comment
основываясь на приведенном выше примере с помощью bitoffdev и @deadly, мы можем увидеть, как str является для конечного пользователя, потому что он дает нам только читаемую строку, а repr предназначен для разработчиков, потому что он дает нам значение, а также тип. Если вы ищете ответы на собеседование, это было бы идеально. - person PSK0007; 13.07.2020

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

person Aaron Hall    schedule 25.01.2015
comment
Разве это не должно быть что-то вроде type(obj).__qualname__? - person Solomon Ucko; 01.12.2018
comment
@SolomonUcko да, в Python 3, похоже, так оно и есть - я искал исходный код, в котором это реализовано, и обновлю свой ответ этой информацией, когда соберу ее. - person Aaron Hall; 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'
person Yong Yang    schedule 21.05.2017
comment
Называть 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(), который автоматически пытается избежать бесконечной рекурсии, заменяя уже представленный объект на ....

person Mangu Singh Rajpurohit    schedule 08.09.2016

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

__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)
person Zer0    schedule 12.01.2016

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

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

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

person asmeurer    schedule 15.11.2012
comment
Я думаю, это упускает суть. Использование eval(repr(obj)) - это проверка работоспособности и практическое правило - если это правильно воссоздает исходный объект, то у вас есть достойная __repr__ реализация. Не предполагается, что вы на самом деле сериализуете объекты таким образом. - person jwg; 06.06.2014
comment
eval по своей сути не опасен. Не опаснее unlink, open или запись в файлы. Должны ли мы прекратить запись в файлы, потому что, возможно, злонамеренная атака может использовать произвольный путь к файлу для помещения содержимого внутрь? Все опасно, если глупые люди тупо используют. Идиотизм опасен. Эффекты Даннинга-Крюгера опасны. eval - это просто функция. - person Luis Masuelli; 01.03.2016

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

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

person Casebash    schedule 17.09.2009
comment
__repr__ ни в коем случае не требуется для возврата действующего выражения Python. - person Mad Physicist; 20.10.2017

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

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

Различия:

str ():

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

repr ():

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

Один аспект, которого не хватает в других ответах. Верно, что в целом закономерность такова:

  • Цель __str__: удобочитаемость
  • Цель __repr__: однозначно, возможно, машиночитаемое через eval

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

person bluenote10    schedule 26.05.2017

В: В чем разница между __str__() и __repr__()?

TL; DR:  Различия между str () / 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() работает, но дело не в этом.)

Дополнительные сведения об обеих парах

  1. Иногда str() и repr() вызываются неявно, что означает, что они вызываются от имени пользователей: когда пользователи выполняют print (Py1 / Py2) или вызывают print() (Py3 +), даже если пользователи не вызывают str() явно, такой вызов выполняется от их имени до отображения объекта.
  2. В оболочке Python (интерактивный интерпретатор), если вы вводите переменную в приглашении >>> и нажимаете RETURN, интерпретатор отображает результаты repr(), неявно вызванного для этого объекта.
  3. Чтобы соединить str() и repr() с __str__() и __repr__(), имейте в виду, что вызовы встроенных функций, то есть str(x) или repr(y), приводят к вызову соответствующих специальных методов их объектов: x.__str__() или y.__repr()__
  4. Реализуя __str__() и __repr__() для ваших классов Python, вы перегружаете встроенные функции (str() и repr()), позволяя передавать экземпляры ваших классов в str() и repr(). Когда такие вызовы сделаны, они поворачиваются и вызывают класс '__str__() и __repr__() (согласно # 3).
person wescpy    schedule 18.08.2020

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

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

person Ijaz Ahmad Khan    schedule 04.04.2017

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

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

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

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

person zangw    schedule 16.11.2015
comment
Он использует __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'
person ShadowWalker    schedule 23.03.2018

>>> 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, будет (когда это возможно) воспроизвести представленный объект.

person BattleDrum    schedule 15.07.2015

__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
person prosti    schedule 06.06.2019

Понять __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

Надеюсь, это поможет вам построить конкретную основу для поиска дополнительных ответов.

person AbstProcDo    schedule 07.12.2017

  1. __str__ должен возвращать строковый объект, тогда как __repr__ может возвращать любое выражение Python.
  2. Если реализация __str__ отсутствует, функция __repr__ используется как резерв. Если реализация функции __repr__ отсутствует, отката нет.
  3. Если функция __repr__ возвращает строковое представление объекта, мы можем пропустить реализацию функции __str__.

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

person Sampath    schedule 18.04.2019

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

person techkuz    schedule 08.05.2018

Каждый объект наследует __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__

person Yilmaz    schedule 06.12.2020