Python etc / Recursive repr

Recursive repr

When you write custom __repr__ for some object, you usually want to include representation of its attributes. You should be careful to call repr() explicitly, since formatting calls str() instead.

Here is a simple example:

class Pair:
    def __init__(self, left, right):
        self.left = left
        self.right = right
        
    def __repr__(self):
        class_name = type(self).__name__
        repr_left = repr(self.left)
        repr_right = repr(self.right)
        return f'{class_name}({repr_left}, {repr_right})'

The problem with calling repr on some other objects is that you can't guarantee it's not the same object and the call isn't recursive:

In : p = Pair(1, 2)
In : p
Out: Pair(1, 2)
In : p.right = p
In : p
Out: [...]
RecursionError: maximum recursion depth exceeded while calling a Python object

To easily solve this problem you can use reprlib.recursive_repr decorator:

@reprlib.recursive_repr()
def __repr__(self):
    class_name = type(self).__name__
    repr_left = repr(self.left)
    repr_right = repr(self.right)
    return f'{class_name}({repr_left}, {repr_right})'

Now it works:

In : p = Pair(1, 2)
In : p.right = p
In : p
Out: Pair(1, ...)