Ответы:
Алекс подвела итог, но, на удивление, была слишком лаконична.
Во-первых, позвольте мне повторить основные моменты в посте Алекса :
__repr__
цель - быть однозначным__str__
цель - быть читабельным__str__
использует содержащиеся объекты__repr__
Реализация по умолчанию бесполезна
В основном это сюрприз, потому что настройки Python по умолчанию довольно полезны. Тем не менее, в этом случае, наличие по умолчанию для __repr__
которого будет действовать так:
return "%s(%r)" % (self.__class__, self.__dict__)
было бы слишком опасно (например, слишком легко попасть в бесконечную рекурсию, если объекты ссылаются друг на друга). Так что Python справляется. Обратите внимание, что есть одно значение по умолчанию, которое является истинным: если __repr__
оно определено, а __str__
не так, объект будет вести себя так, как если бы __str__=__repr__
.
Проще говоря, это означает, что почти каждый реализуемый вами объект должен иметь функционал, __repr__
который можно использовать для понимания объекта. Реализация __str__
является необязательной: делайте это, если вам нужна функциональность «довольно печати» (например, используемая генератором отчетов).
Цель __repr__
состоит в том, чтобы быть однозначным
Позвольте мне выйти и сказать это - я не верю в отладчики. Я действительно не знаю, как использовать любой отладчик, и никогда не использовал его серьезно. Кроме того, я считаю, что большая ошибка отладчиков заключается в их основной природе - большинство ошибок, которые я отлаживал, произошли очень давно, в галактике очень далеко. Это значит, что я с религиозным рвением верю в заготовку леса. Ведение журналов - жизненная основа любой достойной серверной системы, работающей по принципу «забей и забудь». Python облегчает вход в систему: возможно, с некоторыми обертками, специфичными для проекта, все, что вам нужно, это
log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c)
Но вы должны сделать последний шаг - убедиться, что у каждого объекта, который вы реализуете, есть полезный repr, чтобы подобный код мог просто работать. Вот почему возникает вопрос «eval»: если у вас достаточно информации eval(repr(c))==c
, значит, вы знаете все, что нужно знать c
. Если это достаточно просто, по крайней мере, нечетко, сделайте это. Если нет, убедитесь, что у вас достаточно информации о c
любом случае. Я обычно использую Eval-подобный формату: "MyClass(this=%r,that=%r)" % (self.this,self.that)
. Это не означает, что вы действительно можете создать MyClass или что это правильные аргументы конструктора, но это полезная форма для выражения «это все, что вам нужно знать об этом экземпляре».
Примечание: я использовал %r
выше, а не %s
. Вы всегда хотите использовать repr()
[или %r
форматирование символа, эквивалентно] внутри __repr__
реализации, или вы побеждаете цель repr. Вы хотите быть в состоянии дифференцировать MyClass(3)
и MyClass("3")
.
Цель __str__
состоит в том, чтобы быть читабельным
В частности, оно не должно быть однозначным - обратите внимание на это str(3)==str("3")
. Точно так же, если вы реализуете абстракцию IP, иметь такую строку, как 192.168.1.1, просто прекрасно. При реализации абстракции даты / времени str может быть «2010/4/12 15:35:22» и т. Д. Цель состоит в том, чтобы представить ее так, чтобы ее захотел прочитать пользователь, а не программист. Отрежьте ненужные цифры, притворитесь другим классом - пока он поддерживает читабельность, это улучшение.
Контейнер __str__
использует содержащиеся объекты__repr__
Это кажется удивительным, не так ли? Это немного, но насколько читабельно было бы, если бы они использовали их __str__
?
[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]
Не очень. В частности, строки в контейнере слишком легко нарушить его представление строки. Помните, что перед лицом двусмысленности Python сопротивляется искушению угадать. Если вам нужно описанное выше поведение при печати списка, просто
print "[" + ", ".join(l) + "]"
(Вы также можете выяснить, что делать со словарями.
Резюме
Реализуйте __repr__
для любого класса, который вы реализуете. Это должно быть вторая натура. Реализуйте, __str__
если вы считаете, что было бы полезно иметь строковую версию с ошибками на стороне читабельности.
__repr__
было то, что мне нужно для отладки. Спасибо за помощь.
Мое эмпирическое правило: __repr__
для разработчиков, __str__
для клиентов.
__str__
так, чтобы у обычных разработчиков был читаемый объект. С другой стороны, __repr__
для самих разработчиков SDK.
Если вы специально не будете действовать иначе, большинство классов не получат полезных результатов ни для одного из них:
>>> 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__
!
eval(repr(foo))
оценивается ли объект как равный foo
. Вы правы, что он не будет работать вне моих тестовых случаев, так как я не знаю, как импортируется модуль, но это по крайней мере гарантирует, что он работает в некотором предсказуемом контексте. Я думаю, что это хороший способ оценки, если результат __repr__
достаточно явный. Выполнение этого в модульном тесте также помогает обеспечить __repr__
последующие изменения в классе.
eval(repr(spam)) == spam
(хотя бы в правильном контексте), либо eval(repr(spam))
поднимает SyntaxError
. Таким образом вы избежите путаницы. (И это почти верно для встроенных функций и большей части stdlib, за исключением, например, рекурсивных списков, где a=[]; a.append(a); print(eval(repr(a)))
вы можете [[Ellipses]]
...) Конечно, я не делаю это для фактического использования eval(repr(spam))
, за исключением проверки работоспособности в модульных тестах ... но я делать иногда копировать и вставлять repr(spam)
в интерактивной сессии.
__str__
для каждого элемента __repr__
? Мне кажется, что это неправильно, поскольку я реализовал читаемый __str__
объект в своем объекте, и когда он является частью списка, я вижу __repr__
вместо этого более уродливый объект .
eval(repr(x))
не работает даже для встроенных типов: class A(str, Enum): X = 'x'
будет вызывать SyntaxError eval(repr(A.X))
. Это грустно, но понятно. Кстати, на eval(str(A.X))
самом деле работает, но, конечно, только если class A
находится в области видимости - так что, вероятно, это не очень полезно.
str
элемент использования контейнера, repr
потому что [1, 2, 3]
! = ["1", "2, 3"]
.
__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
Короче говоря, цель
__repr__
состоит в том, чтобы быть однозначным и__str__
быть читаемым.
Вот хороший пример:
>>> import datetime
>>> today = datetime.datetime.now()
>>> str(today)
'2012-03-14 09:21:58.130922'
>>> repr(today)
'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'
Прочитайте эту документацию для repr:
repr(object)
Вернуть строку, содержащую печатаемое представление объекта. Это то же самое значение, которое получается при конвертации (обратные кавычки). Иногда полезно иметь доступ к этой операции как к обычной функции. Для многих типов эта функция пытается вернуть строку, которая при передаче в объект выдаст объект с тем же значением
eval()
, в противном случае представление представляет собой строку, заключенную в угловые скобки, которая содержит имя типа объекта вместе с дополнительной информацией. часто в том числе название и адрес объекта. Класс может управлять тем, что эта функция возвращает для своих экземпляров, определяя__repr__()
метод.
Вот документация для ул:
str(object='')
Вернуть строку, содержащую хорошо печатаемое представление объекта. Для строк это возвращает саму строку. Разница с тем
repr(object)
, чтоstr(object)
не всегда пытается вернуть строку, которая является приемлемой дляeval()
; его цель - вернуть строку для печати. Если аргумент не указан, возвращает пустую строку''
.
В чем разница между
__str__
и__repr__
в Python?
__str__
(читается как «строка dunder (двойное подчеркивание)») и __repr__
(читается как «dunder-repper» (для «представления»)) оба являются специальными методами, которые возвращают строки, основанные на состоянии объекта.
__repr__
обеспечивает резервное копирование, если __str__
отсутствует.
Поэтому сначала нужно написать a, __repr__
который позволит вам восстановить экземпляр эквивалентного объекта из строки, которую он возвращает, например, используя eval
или вводя его символ за символом в оболочке Python.
В любое время позже можно написать __str__
для читаемого пользователем строкового представления экземпляра, когда он считает это необходимым.
__str__
Если вы печатаете объект, или передать его format
, str.format
или str
, то если __str__
метод определен, что метод будет вызван, в противном случае, __repr__
будет использоваться.
__repr__
__repr__
Метод вызывается функция встроена repr
и то , что находит отражение в вашем питоне оболочке , когда он вычисляет выражение , которое возвращает объект.
Поскольку он обеспечивает резервное копирование __str__
, если вы можете написать только один, начните с__repr__
Вот встроенная справка repr
:
repr(...)
repr(object) -> string
Return the canonical string representation of the object.
For most object types, eval(repr(object)) == object.
То есть для большинства объектов, если вы напечатаете то, что напечатано repr
, вы сможете создать эквивалентный объект. Но это не реализация по умолчанию.
__repr__
Объект по умолчанию __repr__
( исходный код C Python ) выглядит примерно так:
def __repr__(self):
return '<{0}.{1} object at {2}>'.format(
self.__module__, type(self).__name__, hex(id(self)))
Это означает, что по умолчанию вы будете печатать модуль, из которого объект, имя класса и шестнадцатеричное представление его местоположения в памяти - например:
<__main__.Foo object at 0x7f80665abdd0>
Эта информация не очень полезна, но нет способа определить, как можно точно создать каноническое представление любого конкретного экземпляра, и это лучше, чем ничего, по крайней мере, сказать нам, как мы можем уникально идентифицировать ее в памяти.
__repr__
быть полезно?Давайте посмотрим, насколько это может быть полезно, используя оболочку и datetime
объекты Python . Сначала нам нужно импортировать datetime
модуль:
import datetime
Если мы вызовем datetime.now
оболочку, мы увидим все, что нам нужно, чтобы воссоздать эквивалентный объект datetime. Это создано datetime __repr__
:
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
Если мы печатаем объект datetime, мы видим хороший читабельный (на самом деле, ISO) формат. Это реализовано с помощью datetime __str__
:
>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951
Это простой вопрос - воссоздать потерянный объект, потому что мы не присвоили его переменной, скопировав и вставив из __repr__
вывода, а затем распечатав его, и мы получим его в том же читаемом человеком виде, что и другой объект:
>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180
По мере разработки вы захотите иметь возможность воспроизводить объекты в том же состоянии, если это возможно. Так, например, определяет объект datetime __repr__
( источник Python ). Это довольно сложно из-за всех атрибутов, необходимых для воспроизведения такого объекта:
def __repr__(self):
"""Convert to formal string, for repr()."""
L = [self._year, self._month, self._day, # These are never zero
self._hour, self._minute, self._second, self._microsecond]
if L[-1] == 0:
del L[-1]
if L[-1] == 0:
del L[-1]
s = "%s.%s(%s)" % (self.__class__.__module__,
self.__class__.__qualname__,
", ".join(map(str, L)))
if self._tzinfo is not None:
assert s[-1:] == ")"
s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
if self._fold:
assert s[-1:] == ")"
s = s[:-1] + ", fold=1)"
return s
Если вы хотите, чтобы ваш объект имел более удобочитаемое представление, вы можете реализовать __str__
следующее. Вот как реализуется объект datetime ( источник Python ) __str__
, что он легко делает, потому что у него уже есть функция для отображения в формате ISO:
def __str__(self):
"Convert to string, for str()."
return self.isoformat(sep=' ')
__repr__ = __str__
?Это критика другого ответа здесь, который предлагает установку __repr__ = __str__
.
Установка __repr__ = __str__
глупа - __repr__
это запасной вариант, __str__
и a __repr__
, написанный для разработчиков при отладке, должен быть написан до того, как вы напишите a __str__
.
Вам нужно __str__
только тогда, когда вам нужно текстовое представление объекта.
Определите __repr__
для объектов, которые вы пишете, чтобы вы и другие разработчики имели воспроизводимый пример при использовании его в процессе разработки. Определите, __str__
когда вам нужно удобочитаемое представление строки.
type(obj).__qualname__
?
На странице 358 книги Ханса Петтера Лангтангена «Создание сценариев Python для вычислительной науки » четко сказано, что
__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'
repr
воспроизводить. Лучше думать об этом как о представлении.
Помимо всех ответов, я хотел бы добавить несколько моментов:
1) __repr__()
вызывается, когда вы просто пишете имя объекта на интерактивной консоли Python и нажимаете ввод.
2) __str__()
вызывается при использовании объекта с оператором печати.
3) В случае, если __str__
отсутствует, то печатать и любую функцию, используя str()
вызовы __repr__()
объекта.
4) __str__()
из контейнеров, при вызове будет выполнять __repr__()
метод содержащихся в нем элементов.
5) str()
вызов внутри __str__()
мог потенциально рекурсировать без базового случая и ошибки на максимальной глубине рекурсии.
6) __repr__()
может вызвать, repr()
который попытается автоматически избежать бесконечной рекурсии, заменив уже представленный объект на ...
.
Проще говоря:
__str__
используется, чтобы показать строковое представление вашего объекта, которое будет легко читаться другими.
__repr__
используется , чтобы показать строковое представление на объекте.
Допустим, я хочу создать Fraction
класс, в котором строковое представление дроби равно «(1/2)», а объект (класс дроби) должен быть представлен как «дробь (1,2)».
Таким образом, мы можем создать простой класс Fraction:
class Fraction:
def __init__(self, num, den):
self.__num = num
self.__den = den
def __str__(self):
return '(' + str(self.__num) + '/' + str(self.__den) + ')'
def __repr__(self):
return 'Fraction (' + str(self.__num) + ',' + str(self.__den) + ')'
f = Fraction(1,2)
print('I want to represent the Fraction STRING as ' + str(f)) # (1/2)
print('I want to represent the Fraction OBJECT as ', repr(f)) # Fraction (1,2)
Честно говоря, eval(repr(obj))
никогда не используется. Если вы обнаружите, что используете его, вам следует остановиться, потому что eval
это опасно, а строки - очень неэффективный способ сериализации ваших объектов (используйте pickle
вместо этого).
Поэтому я бы порекомендовал настройку __repr__ = __str__
. Причина заключается в том, что str(list)
вызовы repr
на элементах (я считаю , что это один из самых больших недостатков конструкции Питона , который не был адресован на Python 3). Фактическое repr
, вероятно, не будет очень полезным, как результат print [your, objects]
.
Чтобы это уточнить, по моему опыту, наиболее полезный вариант использования repr
функции - поместить строку в другую строку (используя форматирование строки). Таким образом, вам не нужно беспокоиться о том, чтобы избежать кавычек или чего-то еще. Но учтите, что здесь ничего не eval
происходит.
eval(repr(obj))
- это проверка работоспособности и практическое правило - если это правильно воссоздает исходный объект, то у вас есть достойная __repr__
реализация. Это не означает, что вы действительно сериализуете объекты таким образом.
eval
не является опасным по своей природе. Не более опасно , чем unlink
, open
или записи файлов. Должны ли мы прекратить запись в файлы, потому что, возможно, злонамеренная атака может использовать произвольный путь к файлу для помещения содержимого внутрь? Все опасно, если тупо используется немыми людьми. Идиотизм опасен. Эффекты Даннинг-Крюгера опасны. eval
это просто функция.
Из (неофициальной) справочной вики по Python (архивная копия) от effbot:
__str__
« вычисляет« неформальное »строковое представление объекта. Это отличается от того, __repr__
что оно не обязательно должно быть допустимым выражением Python: вместо него можно использовать более удобное или краткое представление ».
__repr__
ни в коем случае не требуется возвращать пустое выражение Python.
str
- Создает новый строковый объект из данного объекта.
repr
- Возвращает каноническое строковое представление объекта.
Различия:
ул ():
магнезии ():
Один аспект, который отсутствует в других ответах. Это правда, что в целом картина такова:
__str__
: человекочитаемый__repr__
: однозначное, возможно машиночитаемое черезeval
К сожалению, это различие некорректно, поскольку Python REPL, а также IPython используют __repr__
для печати объектов в консоли REPL (см. Связанные вопросы по Python и IPython ). Таким образом, проекты, предназначенные для работы с интерактивной консолью (например, Numpy или Pandas), начали игнорировать вышеприведенные правила и __repr__
вместо этого предоставляют удобочитаемую реализацию.
Из книги Свободный Питон :
Основным требованием для объекта Python является предоставление пригодных для использования строковых представлений, одно из которых используется для отладки и ведения журнала, другое - для представления конечным пользователям. Именно поэтому
специальные методы__repr__
и__str__
существуют в модели данных.
Отличные ответы уже охватывают разницу между __str__
и __repr__
, которая для меня сводится к тому, что первое читается даже конечным пользователем, а второе максимально полезно для разработчиков. Учитывая это, я считаю, что реализация по умолчанию __repr__
часто не может достичь этой цели, потому что в ней отсутствует информация, полезная для разработчиков.
По этой причине, если у меня все достаточно просто __str__
, я, как правило, просто пытаюсь получить лучшее из обоих миров с чем-то вроде:
def __repr__(self):
return '{0} ({1})'.format(object.__repr__(self), str(self))
Важно помнить, что контейнер
__str__
использует объекты__repr__
.
>>> from datetime import datetime
>>> from decimal import Decimal
>>> print (Decimal('52'), datetime.now())
(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 51, 26, 185000))
>>> str((Decimal('52'), datetime.now()))
"(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 52, 22, 176000))"
Python предпочитает однозначность читаемости , __str__
вызовы tuple
вызовов содержащихся объектов __repr__
, «формальное» представление объекта. Хотя формальное представление труднее читать, чем неформальное, оно однозначно и более устойчиво к ошибкам.
__repr__
когда оно ( __str__
) не определено! Итак, вы не правы.
В двух словах:
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'
>>> 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 (когда это возможно) воспроизводят представленный объект.
__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
Понять __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
Надеюсь, что это поможет вам заложить конкретные основания, чтобы найти больше ответов.
__str__
должен возвращать строковый объект, тогда как __repr__
может возвращать любое выражение Python.__str__
реализация отсутствует, __repr__
функция используется как запасной вариант. Нет возврата, если __repr__
реализация функции отсутствует.__repr__
функция возвращает строковое представление объекта, мы можем пропустить реализацию __str__
функции.Источник: https://www.journaldev.com/22460/python-str-repr-functions