reprlib — Альтернативная реализация repr()

Источник: Lib/reprlib.py


Модуль reprlib предоставляет средства для создания представлений объектов с ограничениями на размер получаемых строк. Это используется в отладчике Python и может быть полезно в других контекстах.

Этот модуль предоставляет класс, экземпляр и функцию:

class reprlib.Repr(*, maxlevel=6, maxtuple=6, maxlist=6, maxarray=5, maxdict=4, maxset=6, maxfrozenset=6, maxdeque=6, maxstring=30, maxlong=40, maxother=30, fillvalue='...', indent=None)

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

Аргументы ключевого слова конструктора можно использовать как ярлык для установки атрибутов экземпляра Repr. Это означает, что следующая инициализация:

aRepr = reprlib.Repr(maxlevel=3)

Это эквивалентно:

aRepr = reprlib.Repr()
aRepr.maxlevel = 3

Дополнительные сведения об атрибутах Repr см. в разделе Repr Objects.

Изменено в версии 3.12: Позволяет задавать атрибуты через аргументы ключевых слов.

reprlib.aRepr

Это экземпляр Repr, который используется для обеспечения функции repr(), описанной ниже. Изменение атрибутов этого объекта повлияет на ограничения размера, используемые repr() и отладчиком Python.

reprlib.repr(obj)

Это метод repr() из aRepr. Он возвращает строку, аналогичную той, что возвращает одноименная встроенная функция, но с ограничениями на большинство размеров.

В дополнение к средствам ограничения размера, модуль также предоставляет декоратор для обнаружения рекурсивных вызовов __repr__() и подстановки вместо них строки-заместителя.

@reprlib.recursive_repr(fillvalue='...')

Декоратор для методов __repr__() для обнаружения рекурсивных вызовов в одном потоке. Если выполняется рекурсивный вызов, возвращается значение файла, в противном случае выполняется обычный вызов __repr__(). Например:

>>> from reprlib import recursive_repr
>>> class MyList(list):
...     @recursive_repr()
...     def __repr__(self):
...         return '<' + '|'.join(map(repr, self)) + '>'
...
>>> m = MyList('abc')
>>> m.append(m)
>>> m.append('x')
>>> print(m)
<'a'|'b'|'c'|...|'x'>

Added in version 3.2.

Объекты Repr

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

Repr.fillvalue

Эта строка отображается для рекурсивных ссылок. По умолчанию она принимает значение ....

Added in version 3.11.

Repr.maxlevel

Ограничение на глубину создания рекурсивных представлений. По умолчанию это 6.

Repr.maxdict
Repr.maxlist
Repr.maxtuple
Repr.maxset
Repr.maxfrozenset
Repr.maxdeque
Repr.maxarray

Ограничение на количество записей, представленных для названного типа объекта. По умолчанию 4 для maxdict, 5 для maxarray и 6 для остальных.

Repr.maxlong

Максимальное количество символов в представлении для целого числа. Цифры отбрасываются из середины. По умолчанию это 40.

Repr.maxstring

Ограничение на количество символов в представлении строки. Обратите внимание, что в качестве источника символов используется «нормальное» представление строки: если в представлении необходимы управляющие последовательности, они могут быть искажены при сокращении представления. По умолчанию используется значение 30.

Repr.maxother

Это ограничение используется для контроля размера типов объектов, для которых в объекте Repr не предусмотрен специальный метод форматирования. Оно применяется так же, как и maxstring. По умолчанию используется значение 20.

Repr.indent

Если этот атрибут установлен в None (по умолчанию), вывод будет отформатирован без переносов строк и отступов, как в стандартном repr(). Например:

>>> example = [
...     1, 'spam', {'a': 2, 'b': 'spam eggs', 'c': {3: 4.5, 6: []}}, 'ham']
>>> import reprlib
>>> aRepr = reprlib.Repr()
>>> print(aRepr.repr(example))
[1, 'spam', {'a': 2, 'b': 'spam eggs', 'c': {3: 4.5, 6: []}}, 'ham']

Если indent имеет значение строки, каждый уровень рекурсии размещается на отдельной строке с отступом от этой строки:

>>> aRepr.indent = '-->'
>>> print(aRepr.repr(example))
[
-->1,
-->'spam',
-->{
-->-->'a': 2,
-->-->'b': 'spam eggs',
-->-->'c': {
-->-->-->3: 4.5,
-->-->-->6: [],
-->-->},
-->},
-->'ham',
]

Установка indent в целое положительное значение ведет себя так же, как если бы оно было установлено в строку с таким количеством пробелов:

>>> aRepr.indent = 4
>>> print(aRepr.repr(example))
[
    1,
    'spam',
    {
        'a': 2,
        'b': 'spam eggs',
        'c': {
            3: 4.5,
            6: [],
        },
    },
    'ham',
]

Added in version 3.12.

Repr.repr(obj)

Эквивалент встроенного repr(), который использует форматирование, налагаемое экземпляром.

Repr.repr1(obj, level)

Рекурсивная реализация, используемая repr(). Она использует тип obj для определения метода форматирования, передавая ему obj и level. Методы, специфичные для типа, должны вызывать repr1() для выполнения рекурсивного форматирования, а level - 1 - значение level в рекурсивном вызове.

Repr.repr_TYPE(obj, level)

Методы форматирования для конкретных типов реализуются как методы с именем, основанным на имени типа. В имени метода TYPE заменяется на '_'.join(type(obj).__name__.split()). Диспетчеризация этих методов осуществляется с помощью repr1(). Методы конкретных типов, которым необходимо рекурсивно отформатировать значение, должны вызывать self.repr1(subobj, level - 1).

Подклассификация объектов Repr

Использование динамической диспетчеризации в Repr.repr1() позволяет подклассам Repr добавлять поддержку дополнительных встроенных типов объектов или изменять обработку уже поддерживаемых типов. В этом примере показано, как можно добавить специальную поддержку файловых объектов:

import reprlib
import sys

class MyRepr(reprlib.Repr):

    def repr_TextIOWrapper(self, obj, level):
        if obj.name in {'<stdin>', '<stdout>', '<stderr>'}:
            return obj.name
        return repr(obj)

aRepr = MyRepr()
print(aRepr.repr(sys.stdin))         # prints '<stdin>'
<stdin>