I am looking for a way to implement a custom __repr__
function in Python, that handles recursion Pythonically, while maintaining readability.
I have two classes (Foo and Bar) that point to each other in their attributes. Of course, simply putting e.g.:
class Foo:
def __init__(self, bar):
self.bar = bar
def __repr__(self):
return f'Foo({self.bar})'
@property
def bar(self):
return self._bar
@bar.setter
def bar(self, bar_instance):
if bar_instance is not None:
bar_instance._foo = self
self._bar = bar_instance
class Bar:
def __init__(self, foo=None):
self.foo = None
def __repr__(self):
return f'Bar({self.foo})'
@property
def foo(self):
return self._foo
@foo.setter
def foo(self, foo_instance):
if foo_instance is not None:
foo_instance._bar = self
self._foo = foo_instance
bar = Bar()
foo = Foo(bar)
Would result in a recursion error. Luckily, there's the @recursive_repr()
from reprlib to the rescue. See my implementation below.
from reprlib import recursive_repr
class Foo:
def __init__(self, bar):
self.bar = bar
@recursive_repr()
def __repr__(self):
return f'Foo({self.bar})'
@property
def bar(self):
return self._bar
@bar.setter
def bar(self, bar_instance):
if bar_instance is not None:
bar_instance._foo = self
self._bar = bar_instance
class Bar:
def __init__(self, foo=None):
self.foo = None
@recursive_repr()
def __repr__(self):
return f'Bar({self.foo})'
@property
def foo(self):
return self._foo
@foo.setter
def foo(self, foo_instance):
if foo_instance is not None:
foo_instance._bar = self
self._foo = foo_instance
bar = Bar()
foo = Foo(bar)
However, the custom implementation with fillvalue='...'
doesn't improve readability much, in my opinion. Also, this representation of e.g. the foo
instance - although I know this isn't required - doesn't make it very reproducible, necessarily.
>>> bar = Bar()
>>> foo = Foo(bar)
>>> foo
... Foo(Bar(...))
I am looking for an implementation where I can print a string representation of the foo
instance, instead of printing the triple dots. I would want an output that'd be something like this: Foo(Bar(my_foo_object))
in which I'd be able to define my_foo_object
as the return value of the Foo
__str__
method.
Although in the above example this might not make a ton of sense, in my non-MWE it would provide a more intuitive perspective on the objects and their values.
In brief: is it possible to return a __str__
representation of an object within an objects recursive_repr
at recursion level 1?