RedKnite
RedKnite

Reputation: 1545

How to print a class that can contain itself

I have a class that functions similarly to a list. It can contain itself and that leads to issues printing. Python handles this with replacing the recursive part with Ellipsis. I can do that when the nesting is simple where a = []; a.append(a) by comparing individual items with self, but when there are more complicated relationships this doesn't work. What is a good way to replace recursive parts with Ellipsis or hijack pythons printing mechanism? I tried to construct a list out of the values from self and return str(mylist), but I got a Recursion error from that too.

class foo:
    def __init__(self):
        #stuff happens

    def __repr__(self):
        s = []
        for i in range(self.length):
            if self[i] is self:
                s.append("[...]")
            else:
                s.append(repr(self[i]))
        return f"[{','.join(s)}]"

class bar:
    def __init__(self):
        # stuff happens

    def __repr__(self):
        return str(list(self))

a = foo()
b = foo()
a.append(b)
b.append(a)
print(a)
RecursionError: maximum recursion depth exceeded

a = bar()
b = bar()
a.append(b)
b.append(a)
print(a)
RecursionError: maximum recursion depth exceeded

Upvotes: 3

Views: 172

Answers (1)

RedKnite
RedKnite

Reputation: 1545

Using reprlib, recommended by snakecharmerb, I solved the issue with the decorator reprlib.recursive_repr. The description of that function is:

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

Decorator for __repr__() methods to detect recursive calls within the same thread. If a recursive call is made, the fillvalue is returned, otherwise, the usual __repr__() call is made.

I use the fillvalue "[...]" with brackets because otherwise the result can end up looking like [3, ...] which is not pretty and not the way python formats lists.

@reprlib.recursive_repr("[...]")
def __repr__(self):
    return f"[{','.join(map(repr, self))}]"

Upvotes: 3

Related Questions