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

avatar
Casebash
17 сентября 2009 в 04:27
778486
27
3102

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

Источник

Ответы (27)

avatar
moshez
13 апреля 2010 в 00:56
3035

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

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

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

Samuel
21 февраля 2015 в 19:06
246

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

ThatAintWorking
23 марта 2015 в 21:04
28

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

personal_cloud
29 сентября 2017 в 15:43
17

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

Mickey Perlstein
13 декабря 2018 в 09:21
10

не считая вашего глупого отладчика, я выучил% r, и это все равно стоит голоса

ilias iliadis
8 января 2019 в 18:07
0

@moshez стоит упомянуть, что контейнеры (списки, словари) всегда используют __repr__, а не __str__. print(str([today, today])) печатает [datetime.datetime(2019, 1, 8, 20, 5, 27, 24162), datetime.datetime(2019, 1, 8, 20, 5, 27, 24162)].

NelsonGon
19 июня 2019 в 07:34
0

Безопасно ли eval(repr()) использовать, скажем, в модуле API, который хранит пароли пользователей?

hans
10 июля 2019 в 15:54
1

Я слышал, что переменная l (строчная буква «L») будет синтаксической ошибкой в ​​python 4.0;)

RedGlyph
2 августа 2019 в 11:42
14

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

Marco Sulla
15 января 2020 в 15:16
1

Что касается отладки и ведения журнала, они оба полезны. Если ошибка воспроизводима, отладка упрощается. Если ошибка случайная, необходимо вести журнал.

Philip Couling
24 марта 2020 в 23:09
1

@RedGlyph "когда ваш код выполняется только удаленно на платформе" - это запах кода. Он неявно не имеет модульных тестов и т. Д. Лучшим примером может быть отладка редких стохастических (недетерминированных) ошибок, ошибок IE, которые трудно воспроизвести. Акцент на проблеме, требующей удаленной платформы, а не кода.

RedGlyph
6 сентября 2020 в 11:37
0

@PhilipCouling Обязательно прочтите внимательно и используйте правильный словарный запас, прежде чем сокращать ответы и комментарии других. Мы используем «запах кода», когда при чтении кода обнаруживается что-то, что требует рефакторинга, потому что он скрывает потенциальную проблему, которая может привести к возникновению трудных для поиска ошибок позже или создать плохую общую структуру. Наличие или отсутствие модульного теста - это тоже не то, что вы можете предположить на этом этапе (и это определенно не «неявно»). Наконец, ваше утверждение о «лучшем примере» не имеет никаких оснований, я действительно использовал отладчик для решения тех проблем, которые часто не соответствовали ведению журнала.

Philip Couling
6 сентября 2020 в 21:44
0

@RedGlyph Я знаю, что это , что означает. Код, который может быть выполнен только удаленно, действительно затрудняет тестирование, он подразумевает необходимость в каком-то удаленном ресурсе. Модульное тестирование часто имитирует или заглушает такие ресурсы, что приводит к тому, «почему код не может быть выполнен локально». Если код действительно не может подключиться к отладчику, я бы обеспокоился, какие ошибки были скрыты в результате плохого тестирования. Я действительно считаю, что истинный код, предназначенный только для удаленного доступа, не рекомендуется. Вы говорите, что использовали отладчик для «ошибок, которые трудно воспроизвести» . Это смелое заявление.

kraxor
8 января 2021 в 14:34
1

«Я не верю в отладчики. Я действительно не знаю, как использовать какой-либо отладчик» - это меня взбесило, напоминает мне старый эпизод в Южном парке, где парень никогда не пробовал наркотики, поэтому он уверен, что они злые. Полагаю, мы все боимся неизвестного.

joanis
12 мая 2021 в 18:36
0

Небольшое обновление для последних версий Python 3: вы можете использовать f-строки и по-прежнему вызывать __repr__ встраиваемых данных, добавив !r: вы можете заменить "MyClass(this=%r,that=%r)" % (self.this,self.that) на f"MyClass(this={self.this!r},that={self.that!r})". В противном случае спасибо за этот отличный пост!

avatar
barii
14 мая 2022 в 08:47
0

В основном __str__ или str() используется для создания вывода, который удобочитаем и должен быть предназначен для конечных пользователей. С другой стороны, repr() или __repr__ в основном возвращает каноническое строковое представление объектов, которое служит для отладки и разработки, помогает программистам.

avatar
Vlad Bezden
27 апреля 2022 в 11:19
0

Программисты с предыдущим опытом работы с языками с методом toString склонны реализовывать __str__, а не __repr__. Если вы реализуете только один из этих специальных методов в Python, выберите __repr__.

Из книги Fluent Python Рамальо Лучано.

avatar
JonnyRobbie
5 августа 2021 в 11:36
0

Вы можете получить некоторое представление об этом коде:

class Foo():
    def __repr__(self):
        return("repr")
    def __str__(self):
        return("str")

foo = Foo()
foo #repr
print(foo) #str
avatar
Yilmaz
6 декабря 2020 в 03:31
0

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

представитель позвонил "Человек (имя = '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__

avatar
wescpy
18 августа 2020 в 07:55
10

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

TL; DR: Differences between str()/repr() and __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 или Py вызов print() (Py3 +), даже если пользователи не вызывают str() явно, такой вызов выполняется от их имени до отображения объекта.
  2. В оболочке Python (интерактивный интерпретатор), если вы вводите переменную в приглашении >>> и нажимаете RETURN, интерпретатор отображает результаты repr(), неявно вызванного для этого объекта.
  3. Чтобы соединить str() и repr() с __str__() и __repr__(), осознайте, что вызовы встроенных функций, то есть str(x) или repr(y), приводят к вызову соответствующих специальных методов их объекта: <116134765 > или y.__repr()__
  4. Реализуя __str__() и __repr__() для ваших классов Python, вы перегружаете встроенные функции (str() и repr()), позволяя передавать экземпляры ваших классов в str() и repr(). Когда такие вызовы сделаны, они поворачиваются и вызывают классы '__str__() и __repr__() (по # 3).
avatar
prosti
6 июня 2019 в 16:53
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
avatar
Sampath
18 апреля 2019 в 11:20
3
  1. __str__ должен возвращать строковый объект, тогда как __repr__ может возвращать любое выражение Python.
  2. Если реализация __str__ отсутствует, то функция __repr__ используется в качестве резервной. Если реализация функции __repr__ отсутствует, отката нет.
  3. Если функция __repr__ возвращает строковое представление объекта, мы можем пропустить реализацию функции __str__.

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

avatar
techkuz
8 мая 2018 в 08:49
2

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

avatar
ShadowWalker
23 марта 2018 в 10:30
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'
avatar
AbstProcDo
7 декабря 2017 в 08:03
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

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

avatar
bluenote10
26 мая 2017 в 12:33
8

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

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

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

avatar
Yong Yang
21 мая 2017 в 16:34
44

На странице 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'
jiten
21 декабря 2018 в 13:10
0

Это на стр. №351.

NelsonGon
19 июня 2019 в 07:48
7

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

avatar
Ijaz Ahmad Khan
4 апреля 2017 в 12:35
7

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

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

avatar
Inconnu
4 декабря 2016 в 16:18
11

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

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

Отличия:

str():

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

repr():

  • требуется код, воспроизводящий объект
  • генерирует вывод для разработчика
avatar
Mangu Singh Rajpurohit
8 сентября 2016 в 03:27
43

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

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

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

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

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

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

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

avatar
Zer0
12 января 2016 в 02:53
15

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

__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)
avatar
zangw
16 ноября 2015 в 03:02
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__ содержащихся объектов, «формальное представление» <958034> . Хотя формальное представление труднее читать, чем неформальное, оно недвусмысленно и более устойчиво к ошибкам.

jiten
21 декабря 2018 в 13:48
0

Он использует __repr__, когда он (__str__) не определен! Значит, ты ошибаешься.

avatar
orome
29 октября 2015 в 17:46
5

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

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

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))
avatar
BattleDrum
15 июля 2015 в 10:30
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, будут (когда это возможно) воспроизвести представленный объект.

avatar
Aaron Hall
25 января 2015 в 02:01
135

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

Solomon Ucko
1 декабря 2018 в 01:10
0

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

Aaron Hall♦
1 декабря 2018 в 20:50
0

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

avatar
bitoffdev
25 октября 2013 в 18:38
174

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

Vicrobot
19 августа 2018 в 05:44
1

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

PSK0007
13 июля 2020 в 18:40
0

основываясь на приведенном выше примере с помощью "bitoffdev" и @deadly, мы можем увидеть, как str предназначен для конечного пользователя, потому что он дает нам только читаемую строку, где as repr предназначен для разработчиков, потому что он дает нам значение, а также тип. Если вы ищете ответы на собеседование, это было бы идеально.

avatar
asmeurer
15 ноября 2012 в 10:39
13

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

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

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

jwg
6 июня 2014 в 13:56
19

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

Luis Masuelli
1 марта 2016 в 15:12
8

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

avatar
Ned Batchelder
17 сентября 2009 в 11:35
634

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

Naren Yellavula
15 мая 2019 в 11:45
10

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

Shiplu Mokaddim
9 января 2020 в 13:16
7

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

avatar
Alex Martelli
17 сентября 2009 в 04:49
447

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

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

Steven T. Snyder
15 ноября 2011 в 19:58
43

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

abarnert
20 сентября 2014 в 05:34
4

Я всегда стараюсь убедиться, что либо eval(repr(spam)) == spam (по крайней мере, в правильном контексте), либо eval(repr(spam)) вызывает SyntaxError. Так вы избежите путаницы. (И это почти верно для встроенных функций и большей части stdlib, за исключением, например, рекурсивных списков, где a=[]; a.append(a); print(eval(repr(a))) дает вам [[Ellipses]]…) Конечно, я не делаю этого, чтобы на самом деле используйте eval(repr(spam)), за исключением проверки работоспособности в модульных тестах ... но я делаю иногда копирую и вставляю repr(spam) в интерактивный сеанс.

SuperGeo
26 января 2018 в 14:15
0

Почему бы контейнерам (спискам, кортежам) не использовать __str__ для каждого элемента вместо __repr__? Мне это кажется совершенно неправильным, поскольку я реализовал читаемый __str__ в своем объекте, а когда он является частью списка, я вместо этого вижу более уродливый __repr__.

max
13 января 2019 в 13:26
0

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

mtraceur
6 декабря 2019 в 08:15
0

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

djvg
4 декабря 2020 в 10:32
0

@abarnert: для пользовательского class Spam, eval(repr(spam)) == spam также потребуется реализовать Spam.__eq__, верно? По умолчанию object.__eq__ использует is (docs).

avatar
17 сентября 2009 в 04:35
180

__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
avatar
Casebash
17 сентября 2009 в 04:28
12

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

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

Mad Physicist
20 октября 2017 в 03:23
4

__repr__ ни в коем случае не требуется для возврата действительного выражения Python.