Python - 嵌套 __repr__ 将换行符恢复为“\\n”
Python - nested __repr__ reverts newline to "\\n"
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)
我希望此代码打印:
this
should
all
be
on
separate
lines[this
should
all
be
on
separate
lines[this
should
all
be
on
separate
lines]]
或类似的东西,而是打印
this
should
all
be
on
separate
lines["this\nshould\nall\nbe\non\nseparate\nlines['this\nshould\nall\nbe\non\nseparate\nlines[]']"]
也就是说,当我尝试将一个对象转换为字符串时,它已经在同一 class 的另一个对象的 __repr__
方法中,它会将换行符转换为 \n
,如果我进一步嵌套它会导致 \n
,并且每次我嵌套它时它都会在转义序列之前添加一个额外的反斜杠。
看了this question,好像__repr__
方法认为我其实想要\
和n
这两个字符,但是我没有:我想要转义序列 \n
。有什么方法可以覆盖它并强制将其解释为换行符而不是两个单独的字符吗?
问题是字符串的 repr
将特殊字符转换为转义序列。这意味着,如果您在具有特殊字符的字符串上递归调用 repr
,反斜杠将堆积起来:
>>> 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'"
您遇到此问题是因为您的 __repr__
调用列表中的 str
,而列表的 str
使用 repr
( 而不是 str
) 列表中的每一项:
>>> print('First line\nSecond line')
First line
Second line
>>> print(['First line\nSecond line'])
['First line\nSecond line']
请注意,\n
出现在这里,就像在第一个示例中对字符串本身调用 repr
一样。那是因为列表调用 repr
对其内容进行显示。
因此,通过执行 str([...])
,您正在对列表的内容调用 repr
,这意味着您正在递归调用 repr
嵌套对象,这意味着反斜杠堆积如你所见。
如果你想避免这种情况,你需要避免在嵌套对象上调用 repr。您可以通过使用 join
手动制作字符串来完成此操作,类似于您已经执行的操作,而不是在列表中调用 str
:
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
然后你的 print(myClass)
给出了你想要的结果。
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)
我希望此代码打印:
this
should
all
be
on
separate
lines[this
should
all
be
on
separate
lines[this
should
all
be
on
separate
lines]]
或类似的东西,而是打印
this
should
all
be
on
separate
lines["this\nshould\nall\nbe\non\nseparate\nlines['this\nshould\nall\nbe\non\nseparate\nlines[]']"]
也就是说,当我尝试将一个对象转换为字符串时,它已经在同一 class 的另一个对象的 __repr__
方法中,它会将换行符转换为 \n
,如果我进一步嵌套它会导致 \n
,并且每次我嵌套它时它都会在转义序列之前添加一个额外的反斜杠。
看了this question,好像__repr__
方法认为我其实想要\
和n
这两个字符,但是我没有:我想要转义序列 \n
。有什么方法可以覆盖它并强制将其解释为换行符而不是两个单独的字符吗?
问题是字符串的 repr
将特殊字符转换为转义序列。这意味着,如果您在具有特殊字符的字符串上递归调用 repr
,反斜杠将堆积起来:
>>> 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'"
您遇到此问题是因为您的 __repr__
调用列表中的 str
,而列表的 str
使用 repr
( 而不是 str
) 列表中的每一项:
>>> print('First line\nSecond line')
First line
Second line
>>> print(['First line\nSecond line'])
['First line\nSecond line']
请注意,\n
出现在这里,就像在第一个示例中对字符串本身调用 repr
一样。那是因为列表调用 repr
对其内容进行显示。
因此,通过执行 str([...])
,您正在对列表的内容调用 repr
,这意味着您正在递归调用 repr
嵌套对象,这意味着反斜杠堆积如你所见。
如果你想避免这种情况,你需要避免在嵌套对象上调用 repr。您可以通过使用 join
手动制作字符串来完成此操作,类似于您已经执行的操作,而不是在列表中调用 str
:
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
然后你的 print(myClass)
给出了你想要的结果。