Питання Різниця між __str__ і __repr__?


Яка різниця між __str__ і __repr__ в Python?


2111
2017-09-17 04:27


походження




Відповіді:


Олексій підсумовано добре, але, на диво, було надто стислим.

По-перше, дозвольте мені повторити основні моменти в Росії Пост Алекса:

  • Реалізація за умовчанням є марною (важко думати про те, що не буде, але так)
  • __repr__ мета - бути однозначним
  • __str__ Мета - бути читабельним
  • Контейнерні __str__ використовує містять об'єкти __repr__

Реалізація за замовчуванням є марною

Це, в основному, сюрприз, оскільки за замовчуванням Python досить корисні. Однак, у цьому випадку, за замовчуванням для __repr__ який буде діяти, як:

return "%s(%r)" % (self.__class__, self.__dict__)

було б надто небезпечно (наприклад, надто легко потрапити в нескінченну рекурсію, якщо об'єкти ототожнюють один одного). Отже, Python викидає. Зверніть увагу, що існує один типовий за замовчуванням: if __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__ реалізація, або ви перемагаєте ціль репри. Ви хочете мати можливість диференціювати MyClass(3) і MyClass("3").

Мета __str__ має бути читабельним

Зокрема, це не має на меті бути однозначним - зверніть увагу str(3)==str("3"). Точно так само, якщо ви реалізуєте абстрактність IP-адреси, то пам'ятка, яка виглядає так, як виглядає як 192.168.1.1, просто добре. Застосовуючи абстракцію дати / часу, str може бути "2010/4/12 15:35:22" тощо. Метою є представлення його таким чином, щоб користувач, а не програміст, хотів би його прочитати. Відрубайте непотрібні цифри, прикидайтеся деяким іншим класом - як довго це підтримує читабельність, це поліпшення.

Контейнерні __str__ використовує містять об'єкти __repr__

Це здається дивним, чи не так? Це трохи, але як читається

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

бути? НЕ дуже. Зокрема, рядки в контейнері виявилися б надто легкими, щоб порушити його представлення рядків. Пам'ятайте, що, незважаючи на невизначеність, Python протистоїть спокусі вгадати. Якщо ви хочете описати вище поведінку, коли ви друкуєте список, просто

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

(можливо, ви також можете з'ясувати, що робити з словниками.

Резюме

Реалізувати __repr__ для будь-якого класу, який ви реалізуєте. Це має бути другий характер. Реалізувати __str__ якщо ви вважаєте, що було б корисно мати рядкову версію, яка помиляється на стороні більшої читабельності, на користь більшої двозначності.


2174
2018-04-13 00:56



Напевно, не згоден з вашою думкою, що налагодження - це не шлях. Для розробки використовуйте відладчик (та / або реєстрацію) для реєстрації виробництва. За допомогою відладчика ви бачите все, що сталося помилки під час виникнення проблеми. Ви можете побачити повну картину. Якщо ви не записуєте ВСЕ, ви не можете це зробити. Плюс якщо ви реєструєте все, що ви збираєтеся, вам доведеться пройти через тонни даних, щоб отримати те, що ви хочете. - Samuel
Відмінна відповідь (крім біт про те, що не використовує відладчики). Я просто хотів би додати посилання на це інші питання та питання про вул проти Unicode в Python 3 які можуть бути актуальними для обговорення для людей, які зробили перемикач. - ThatAintWorking
", ".join(l) - використовує погану практику використання букв "L" в якості назви змінної. Давайте не навчаємо програмуванню новачкам такі приклади в авторитетних джерелах. - Nikolay Prokopyev
plus1 для відладчиків марні, і не варто робити вартість копійки. Замість цього отримаєте пропускну здатність реєстрації. І так, це було добре написане повідомлення. Виявилось __repr__ було те, що мені потрібно для налагодження. Дякую за твою допомогу. - personal_cloud


Моє правило: __repr__ це для розробників __str__ це для клієнтів.


369
2017-09-17 11:35





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

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


319
2017-09-17 04:49



У моїх одиничних тестах я завжди перевіряю це eval(repr(foo)) оцінює об'єкт, що дорівнює foo. Ви маєте рацію, що вона не працюватиме поза моїми тестовими випадками, оскільки я не знаю, як імпортується модуль, але це, як мінімум, гарантує, що він працює. дещо передбачуваний контекст. Я думаю, що це хороший спосіб оцінити, чи є результатом __repr__ явно достатньо Це також допомагає забезпечити це __repr__ слідує зміни класу. - Steven T. Snyder
Я завжди намагаюся переконатися в цьому eval(repr(spam)) == spam (принаймні в потрібному контексті), або eval(repr(spam)) піднімає а SyntaxError. Таким чином, ви уникаєте плутанини. (І це майже вірно для вбудованих і більшості stdlib, за винятком, наприклад, рекурсивних списків, де a=[]; a.append(a); print(eval(repr(a))) дає тобі [[Ellipses]]...) Звичайно, я цього не роблю насправді використовувати  eval(repr(spam)), крім як перевірки здорового глузду в одиничних тестах ... але я робити іноді копіювати та вставляти repr(spam) в інтерактивний сеанс. - abarnert
plus1 для пояснення цього __str__ реалізується з точки зору __repr__. Здається, щось іншим пропущеним посадам. - personal_cloud
Чому б не використовувати контейнери (списки, кортежі) __str__ для кожного елемента замість __repr__? Здається мені неправильним, тому що я реалізував читабельний __str__ в моєму об'єкті, і коли він є частиною списку, я бачу жахливіше __repr__ замість цього. - SuperGeo


__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

143
2017-09-17 04:35





Одним словом, мета __repr__ повинен бути однозначним і __str__ повинен бути   читабельний

Ось хороший приклад:

>>> import datetime
>>> today = datetime.datetime.now()
>>> str(today)
'2012-03-14 09:21:58.130922'
>>> repr(today)
'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'

Прочитайте цю документацію для перегляду:

repr(object)

Повернути рядок, що містить друковане представлення об'єкта. Це та ж величина, яку дають конверсії (зворотний   лапки) Іноді корисно мати доступ до цієї операції як   звичайна функція. Для багатьох типів ця функція робить спробу   щоб повернути рядок, який дає об'єкт з тим самим значенням, коли   перейшов до eval(), в іншому випадку представлення - це рядок, вкладена в   кутові дужки, що містить назву типу об'єкта   разом з додатковою інформацією, що часто містить назву та   адреса об'єкта. Клас може контролювати, що повертається ця функція   для його випадків, визначивши a __repr__() метод

Ось документація для str:

str(object='')

Повернути рядок, що містить чітко друковану версію   Представлення об'єкта. Для рядків це повертає рядок   сама по собі Різниця з repr(object)чи це str(object) не   завжди намагайтеся повернути прийнятне для нього рядок eval(); його   Мета - повернути рядок для друку. Якщо аргумент не дано, то повертається   порожня рядок ''.


114
2017-10-25 18:38





Яка різниця між __str__ і __repr__ в Python?

__str__ (читається як "dunder (подвійне підкреслення)") і __repr__ (читаються як "dunder-repper" (для "представлення")) - це обидва спеціальні методи, які повертають рядки на основі стану об'єкта.

__repr__ забезпечує резервну поведінку, якщо __str__ відсутня.

Тому треба спочатку написати a __repr__ що дозволяє вам переінсталювати еквівалентний об'єкт з рядок, який він повертає, наприклад, використовуючи eval або набравши його у символічному символі в оболонці Python.

У будь-який час пізніше можна написати a __str__ для зручного для читання рядкового представлення екземпляра, коли хто вважає це необхідним.

__str__

Якщо ви надрукуєте об'єкт або передаєте його format, str.format, або str, то якщо a __str__ метод визначений, цей метод буде викликаний, інакше __repr__ буде використано.

__repr__

The __repr__ Метод називається вбудованою функцією repr і це відбивається на оболонці python при оцінці виразу, який повертає об'єкт.

Оскільки він забезпечує резервну копію для __str__, якщо ви можете тільки написати одну, почніть з __repr__

Ось вбудована допомога repr:

repr(...)
    repr(object) -> string

    Return the canonical string representation of the object.
    For most object types, eval(repr(object)) == object.

Тобто для більшості об'єктів, якщо ви вводите, що надруковано repr, ви повинні мати можливість створити еквівалентний об'єкт. Але це не стандартна реалізація.

За замовчуванням виконується __repr__

Об'єкт за замовчуванням __repr__ є (C Python джерело) щось на зразок:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

Це означає, що за замовчуванням ви друкуєте модуль, з якого знаходиться об'єкт, ім'я класу та шістнадцяткове подання його розташування в пам'яті - наприклад:

<__main__.Foo object at 0x7f80665abdd0>

Ця інформація не є дуже корисною, але немає можливості вивести, як можна точно створити канонічне зображення будь-якого конкретного примірника, і це краще, ніж нічого, принаймні розповісти нам, як ми можемо однозначно ідентифікувати його в пам'яті.

Як можна __repr__ бути корисним?

Давайте подивимося, наскільки це корисно, використовуючи оболонку Python і datetime об'єкти Спочатку нам потрібно імпортувати datetime модуль:

import datetime

Якщо ми зателефонуємо datetime.now в оболонці ми побачимо все, що нам потрібно, щоб відтворити еквівалентний об'єкт дати. Це створено за датоюtime __repr__:

>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)

Якщо ми надрукуємо об'єкт datetime, ми бачимо хороший формат, читаний для читання (насправді, ISO). Це реалізовано за датою часу __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 = ", ".join(map(str, L))
    s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s)
    if self._tzinfo is not None:
        assert s[-1:] == ")"
        s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
    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__, написаний для використання розробниками при налагодженні, слід написати перед тим, як написати __str__.

Вам потрібно а __str__ тільки тоді, коли вам потрібне текстове подання об'єкта.

Висновок

Визначте __repr__ для об'єктів, які ви пишете, ви та інші розробники мають відтворений приклад, коли використовуєте його під час розробки. Визначте __str__ коли вам потрібна людська читана рядок уявлення про це.


84
2018-01-25 02:01





Крім всіх наведених відповідей я хотів би додати кілька пунктів:

1) __repr__() викликається, коли ви просто напишите ім'я об'єкта на інтерактивній консолі python і натисніть клавішу Enter.

2) __str__() викликається, коли ви використовуєте об'єкт з оператором print.

3) У випадку, якщо __str__ відсутній, потім друкуйте та використовуйте будь-яку функцію str() викликає __repr__() об'єкта

4) __str__() з контейнерів, коли він буде викликаний __repr__() Метод його складових елементів.

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

6) __repr__() може зателефонувати repr() який буде намагатися автоматично уникати нескінченної рекурсії, замінюючи вже представлений об'єкт з ....


12
2017-09-08 03:27





З усією чесністю eval(repr(obj)) ніколи не використовується Якщо ви впевнені, що використовуєте це, ви повинні зупинитися, тому що eval це небезпечно, і рядки - це дуже неефективний спосіб серіалізації ваших об'єктів (use pickle замість цього).

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

Щоб визначити це, на мій досвід, найбільш корисним випадком використання repr Функція полягає в тому, щоб помістити рядок в інший рядок (використовуючи форматування рядка). Таким чином, вам не доведеться турбуватися про втечу котирувань або що-небудь. Але зауважте, що немає eval відбувається тут


11
2017-11-15 10:39



Я думаю, що це здогадується. Використання eval(repr(obj)) це випробування на здоровий глузд і правило - якщо це правильно відтворює оригінальний об'єкт, то у вас є пристойний __repr__ реалізація Це не означає, що ви дійсно серіалізуєте об'єкти таким чином. - jwg
eval не по суті небезпечний. Не небезпечніше, ніж unlink, open, або написання файлів. Чи повинні ми перестати писати файли, тому що, можливо, шкідлива атака може використовувати довільний путь файлів для розміщення вмісту всередині? Все небезпечно, якщо його спотворюють безглузді люди. Ідіоцизм небезпечний. Ефекти Dunning-Kruger небезпечні. eval це просто функція - Luis Masuelli


Простіше кажучи:

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

__repr__ використовується для показу строкового подання в об'єкт

Скажімо, я хочу створити Fraction клас, де строкове подання фракції є '(1/2)', а об'єкт (клас Дракти) повинен бути представлений як '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)

10
2018-01-12 02:53