以下代码抛出RuntimeError: maximum recursion depth exceeded while getting the str of an object
。我可以用两种不同的方式解决无限递归,但我不明白为什么每种修复都有效,因此不知道使用哪种,或者两种方法是否正确。
class FileError( Exception ):
def __init__( self, filename=None, *a, **k ):
#Fix 1: remove super
super( FileError, self ).__init__( self, *a, **k )
self.filename = filename
def __repr__( self ):
return "<{0} ({1})>".format( self.__class__.__name__, self.filename )
#Fix 2: explicitly define __str__
#__str__ = __repr__
print( FileError( "abc" ) )
如果我删除super
,代码会运行,但不会打印任何内容。这没有意义,因为根据这篇文章Difference between __str__ and __repr__ in Python,省略__str__
将会调用__repr__
,但这似乎不会发生在这里。
相反,如果我继续调用super
并添加__str__ = __repr__
,那么我会获得预期的输出并且没有递归。
有人可以解释为什么存在无限递归,为什么每次更改都会解析inifinte递归,以及为什么一个修复可能比另一个更优先?
答案 0 :(得分:4)
不要将self
作为第一个参数传递给__init__
。这导致了递归。
应该是:
super( FileError, self ).__init__( filename, *a, **k )
引起递归是因为
>>> print Exception("Abc")
Abc
Exception
打印第一个参数。所以当你初始化FileError
的基类,即Exception
,self
继承__str__
从它的父节点打印第一个参数(希望你看到语句中的递归) ..因此你获得了无限的递归。
__str__ = __repr__
会覆盖继承的__str__
并减轻无限递归。
答案 1 :(得分:4)
此行不正确:
super( FileError, self ).__init__( self, *a, **k )
您需要在self
中传递super()
,但不能再将其作为__init__
的参数传递。所以需要:
super( FileError, self ).__init__( *a, **k )
答案 2 :(得分:3)
您的super
调用错误:self
不应再次提供,它已由super
注入。这样,file_error.args[0] is file_error
因为您将self
作为额外参数传递给异常构造函数。这应该很明显为什么修复#1(完全删除超级调用)有帮助,但当然最好的解决方法是传递正确的参数:
super(FileError, self).__init__(filename, *a, **k)
无限递归的原因:首先,只有object.__str__
代表__repr__
; BaseException
分别定义了__str__
和__repr__
,因此异常的str()
会调用该重载,而不是__repr__
。 BaseException.__str__
通常为prints the args tuple(使用repr
),但当它包含单个参数时,它会打印该单个参数的str()
。
再次调用BaseException.__str__
,依此类推。修复#2首先不输入BaseException.__str__
,而是使用不会触及args元组的__repr__
来阻止此循环。