Python:打印自定义异常时超出了最大递归深度

时间:2014-01-27 21:32:47

标签: python recursion custom-exceptions repr

以下代码抛出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递归,以及为什么一个修复可能比另一个更优先?

3 个答案:

答案 0 :(得分:4)

不要将self作为第一个参数传递给__init__。这导致了递归。

应该是:

super( FileError, self ).__init__( filename, *a, **k )

引起递归是因为

>>> print Exception("Abc")
Abc

Exception打印第一个参数。所以当你初始化FileError的基类,即Exceptionself继承__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__来阻止此循环。