Скажите IPython использовать объект `__str__` вместо` __repr__` для вывода

По умолчанию, когда IPython отображает объект, он, кажется, использует __repr__.

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

Теперь предположим, что мы написали конкретный класс, и мы хотели бы, чтобы IPython выдавал удобочитаемый вывод по умолчанию (т.е. без явного вызова print или __str__). Мы не хотим выдумывать это, делая наше задание класса __repr__ do __str__. Это нарушит правила.

Можно ли указать IPython для вызова __str__ по умолчанию для определенного класса?

Ответ 1

Это, безусловно, возможно; вам просто нужно реализовать метод экземпляра _repr_pretty_(self). Это описано в документации для IPython.lib.pretty. Его реализация может выглядеть примерно так:

class MyObject:
    def _repr_pretty_(self, p, cycle):
       p.text(str(self) if not cycle else '...')

Параметр p представляет собой экземпляр IPython.lib.pretty.PrettyPrinter, методы которого вы должны использовать для вывода текстового представления объекта, который вы форматирование. Обычно вы используете p.text(text), который просто добавляет заданный text verbatim к форматированному представлению, но вы можете делать такие вещи, как начальная и конечная группы, если ваш класс представляет коллекцию.

Параметр cycle является логическим, указывающим, обнаружен ли опорный цикл, то есть, пытаетесь ли вы дважды форматировать объект в одном стеке вызовов (что приводит к бесконечному циклу). Может быть или нет необходимости рассматривать его в зависимости от того, какой объект вы используете, но это не повредит.


В качестве бонуса, если вы хотите сделать это для класса, код которого вы не имеете доступа (или, точнее, не хотите) изменять, или если вы просто хотите сделать временное изменение для вы можете использовать метод форматирования отображения for_type для IPython, как показано в этом примере настройки int display. В вашем случае вы будете использовать

get_ipython().display_formatter.formatters['text/plain'].for_type(
    MyObject,
    lambda obj, p, cycle: p.text(str(obj) if not cycle else '...')
)

с MyObject, конечно, представляя тип, который вы хотите настроить для печати. Обратите внимание, что функция лямбда несет ту же подпись, что и _repr_pretty_, и работает одинаково.