Разница между __str__и __repr__. (2/5)

python magic-methods repr




Answer 6 Aaron Hall


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

__str__ (читается как «dunder (двойное подчеркивание) строка») и __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__ - это ( источник на 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 в оболочке, мы увидим все, что нам нужно для воссоздания эквивалентного объекта datetime. Это создается datetime __repr__ :

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

Если мы печатаем объект datetime, мы видим хороший читабельный (на самом деле, ISO) формат. Это реализуется __str__ из datetime :

>>> 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__ 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__ только когда вам нужно текстовое представление объекта.

Conclusion

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




Answer 7 Yong Yang


На странице 358 книги Ханса Петтера Лангтангена «Создание сценариев Python для вычислительной науки » четко сказано, что

  • В __repr__ цели в полной строковое представление объекта;
  • __str__ это вернуть хорошую строку для печати.

Поэтому я предпочитаю понимать их как

  • repr = воспроизводить
  • str = строка (представление)

с точки зрения пользователя,хотя это недоразумение,которое я совершил,изучая Питона.

Небольшой,но хороший пример приведен на этой же странице следующим образом:

Example

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'



Answer 8 Mangu Singh Rajpurohit


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

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

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

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

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

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

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




Answer 9 Zer0


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

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

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

Допустим, я хочу создать класс Fraction ,в котором строковое представление дроби равно '(1/2)', а объект (класс Fraction) должен быть представлен как 'Fraction (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)



Answer 10 asmeurer


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

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

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