Python:打印自定义异常时超出最大递归深度
Posted
技术标签:
【中文标题】Python:打印自定义异常时超出最大递归深度【英文标题】:Python: Maximum recursion depth exceeded when printing custom exception 【发布时间】:2014-02-18 22:58:16 【问题描述】:以下代码抛出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__
,那么我会得到预期的输出并且没有递归。
有人可以解释为什么存在无限递归,为什么每次更改都会解决无限递归,以及为什么一种修复可能优于另一种修复?
【问题讨论】:
__repr__
未被用作__str__
的原因是基本异常定义了__str__
。
【参考方案1】:
您的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__
。
【讨论】:
@BleedingFingers 是的,很有可能。感谢您的提醒。 @delnan 我将此标记为最正确的答案,因为它回答了递归发生的原因,并且这样做很好地描述了super()
的工作原理。我现在明白为什么会有递归,也明白我必须覆盖__str__
。【参考方案2】:
不要将self
传递给__init__
作为第一个参数。这导致了递归。
应该是:
super( FileError, self ).__init__( filename, *a, **k )
递归是因为
>>> print Exception("Abc")
Abc
Exception
打印第一个参数。因此,当您使用 self
初始化 FileError
的基类,即 Exception
时,它从打印第一个参数的父级继承 __str__
(希望您在语句中看到递归)。因此,您将获得无限递归.
__str__ = __repr__
覆盖继承的__str__
并缓解无限递归。
【讨论】:
这究竟是如何导致递归的?我自己很快就发现了这个错误,但我对这如何导致str
无限递归而repr
工作正常感到目瞪口呆。
我想我只是自己想通了。不过,我仍然很想看看你的解释。
我认为这是因为 self
被用作基本异常 message
参数。所以 str 在message
上被调用,它调用str
,它在消息上调用str
,等等。【参考方案3】:
此行不正确:
super( FileError, self ).__init__( self, *a, **k )
您需要在super()
中传递self
,但不能再次作为__init__
的参数。所以它必须是:
super( FileError, self ).__init__( *a, **k )
【讨论】:
以上是关于Python:打印自定义异常时超出最大递归深度的主要内容,如果未能解决你的问题,请参考以下文章
RecursionError:重命名列条目后调用 Python 对象时超出最大递归深度
MongoEngine 0.5:RuntimeError:调用 Python 对象时超出最大递归深度