примеры - repr python 3




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

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

__str__ (читать как «dunder (double-underscore) string») и __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__

Объектом по умолчанию __repr__ является ( C Python source ) что-то вроде:

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's __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__ next. Вот как объект 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__ когда вам понадобится его читаемое пользователем строковое представление.

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


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


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

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'

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

>>> class Sic(object): pass
... 
>>> print str(Sic())
<__main__.Sic object at 0x8b7d0>
>>> print repr(Sic())
<__main__.Sic object at 0x8b7d0>
>>> 

Как вы видите - никакой разницы и никакой информации, кроме класса и объекта. Если вы только переопределите один из двух ...:

>>> 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__ же однозначным, насколько возможно, даже если это мешает нечеткой недостижимой цели сделать возвращаемое значение __eval__ приемлемым в качестве входа в __eval__ !


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

Настолько яснее из blog

str как toString. созданный таким образом, что вы можете распечатать репрезентацию данных, это как сериализация или рассол. Как я могу воссоздать этот объект, если мне нужно это сделать, используя eval ()

>>> import datetime
>>> now = datetime.datetime.now() 
>>> str(now)
'2015-04-04 20:51:31.766862'
>>> repr(now)
'datetime.datetime(2015, 4, 4, 20, 51, 31, 766862)'
>>mydate = eval(repr(now))

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

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

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

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

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

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

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

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

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

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


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

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

__repr__ используется для отображения строкового представления объекта.

Предположим, что я хочу создать класс Fraction где строковое представление фракции равно «(1/2)», а объект (класс фракции) должен быть представлен как «Фракция (1,2)»

Таким образом, мы можем создать простой класс фракций:

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)

С http://pyref.infogami.com/__str__ от effbot:

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


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


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

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

Различия:

ул ():

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

магнезии ():

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

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

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

  • Реализация по умолчанию бесполезна (трудно думать о том, чего не было бы, но да)
  • Цель __repr__ - быть однозначной
  • Цель __str__ - быть читаемой
  • Контейнер __str__ использует содержащиеся объекты __repr__

Внедрение по умолчанию бесполезно

Это в большинстве своем сюрприз, потому что по умолчанию Python имеет довольно полезную ценность. Тем не менее, в этом случае, имея значение по умолчанию для __repr__ которое будет действовать следующим образом:

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

было бы слишком опасно (например, слишком легко попасть в бесконечную рекурсию, если объекты ссылаются друг на друга). Так что Питон уходит. Обратите внимание, что существует одно значение по умолчанию, которое является истинным: если __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 любом случае. Обычно я использую условный формат: "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__ если вы считаете, что было бы полезно иметь строчную версию, которая ошибается на стороне большей удобочитаемости в пользу большей двусмысленности.


"A basic requirement for a Python object is to provide usable 
 string   representations of itself, one used for debugging and
 logging, another for presentation to end users. That is why the  
 special methods __repr__ and __str__ exist in the data model."

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





repr