Как мне обработать рекурсивные repr () в Python? - PullRequest
12 голосов
/ 18 мая 2010

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

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

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

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

Ответы [ 2 ]

7 голосов
/ 18 мая 2010

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

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

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)
5 голосов
/ 28 января 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...