class MyClass:
def __init__(self):
self.list_ = []
def __repr__(self):
return '\n'.join(['this','should','all','be','on','separate','lines']) + str([str(list_val) for list_val in self.list_])
myClass = MyClass()
myClass.list_.append(MyClass())
myClass.list_[0].list_.append(MyClass())
print(myClass)
I would expect this code to print:
this
should
all
be
on
separate
lines[this
should
all
be
on
separate
lines[this
should
all
be
on
separate
lines]]
or something similar, but instead it prints
this
should
all
be
on
separate
lines["this\nshould\nall\nbe\non\nseparate\nlines['this\\nshould\\nall\\nbe\\non\\nseparate\\nlines[]']"]
That is, when I try to convert an object to a string while already inside the __repr__
method of another object of the same class, it turns a newline into \n
, and if I nest it further it results in \\n
, and each time I nest it it adds an additional backslash before the escape sequence.
After reading this question, it seems that the __repr__
method thinks I actually want the two characters \
and n
, but I don't: I want the escape sequence \n
. Is there any way to override this and force it to interpret it as a newline rather than two separate characters?
The problem is that the repr
of a string converts special characters to escape sequences. This means if you call repr
recursively on a string with special characters, backslashes will pile up:
>>> print("First line\nSecond line")
First line
Second line
>>> print(repr("First line\nSecond line"))
'First line\nSecond line'
>>> print(repr(repr("First line\nSecond line")))
"'First line\\nSecond line'"
You are encountering this because your __repr__
calls str
on a list, and the str
of a list uses repr
(not str
) on each item in the list:
>>> print('First line\nSecond line')
First line
Second line
>>> print(['First line\nSecond line'])
['First line\nSecond line']
Note that the \n
appears here, just like it did for calling repr
on the string itself in the first example. That's because lists call repr
on their contents to display themselves.
So by doing str([...])
, you are calling repr
on the contents of your list, which means you're calling repr
recursively your nested objects, which means backslashes pile up as you saw.
If you want to avoid this, you need to avoid calling repr on the nested objects. You can do this by manually crafting a string using join
, similar to what you already did, instead of calling str
on a list:
def __repr__(self):
innerRepr = '['+'\n'.join(str(list_val) for list_val in self.list_) + ']' if self.list_ else ''
return '\n'.join(['this','should','all','be','on','separate','lines']) + innerRepr
Then your print(myClass)
gives your desired result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With