Подтвердить что ты не робот

Как обрабатывать рекурсивную функцию repr() в Python?

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

Например, вот что делает встроенный list:

>>> x = []
>>> x.append(x)
>>> repr(x)
'[[...]]'

Типы контейнеров, написанные на C для CPython, могут достичь этой функциональности, используя Py_ReprEnter и Py_ReprLeave. Есть ли эквивалентная функциональность в pure-Python, или мне нужно создать свой собственный?

4b9b3361

Ответ 1

Вы можете создать свой собственный, но это немного больно, если вы хотите сделать это правильно: вы не должны хранить флаг "быть объявленным маркером" на самом объекте, потому что это не потокобезопасно. Вместо этого вы можете сохранить локальный набор из ваших экземпляров, которые будут опубликованы.

Более дешевое решение должно зависеть от встроенного repr, который заботится о рекурсии, например:

def __init__(self, *list):
    self._list= list
def __repr__(self):
    return 'mything('+repr(self._list)[1:-1]+')')

Пока один объект в цикле рекурсии вызывает Py_ReprEnter, repr не может сформировать полный цикл.

Как создать поток-локальный набор экземпляров?

С помощью threading модуль:

class MyThing(object):
    _local= threading.local()
    _local.reprs= set()

    def __repr__(self):
        reprs= MyThing._local.reprs
        sid= id(self)
        if sid in reprs:
            return 'MyThing(...)'
        try:
            reprs.add(sid)
            return 'MyThing(%r)' % self.something
        finally:
            reprs.remove(sid)

Ответ 2

Если вы используете Python 3, вы можете использовать декоратор reprlib.recursive_repr.