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

and*_*cal 9 python recursion repr custom-exceptions

以下代码抛出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" ) )
Run Code Online (Sandbox Code Playgroud)

如果我删除super,代码运行但不打印任何东西.这没有意义,因为根据这篇文章,Python中的__str__和__repr__之间的区别,省略__str__将调用,__repr__但这似乎不会发生在这里.

相反,如果我继续调用super并添加__str__ = __repr__,那么我得到预期的输出并且没有递归.

有人可以解释为什么无限递归存在,为什么每次更改都会解决inifinte递归,以及为什么一个修复可能比另一个更优先?

小智 4

您的super调用是错误的:self不应再次提供,它已由 注入super。这样,file_error.args[0] is file_error因为您将self作为额外参数传递给异常构造函数。这应该很明显为什么修复#1(完全删除 super 调用)有帮助,但当然最好的修复是传递正确的参数

super(FileError, self).__init__(filename, *a, **k)
Run Code Online (Sandbox Code Playgroud)

无限递归的原因:首先,仅object.__str__委托给__repr__; BaseException分别定义__str____repr__,因此str()异常会调用重载,而不是您的__repr__. BaseException.__str__通常打印 args 元组(将使用repr),但当它包含单个参数时,它会打印该str()单个参数的 。

这会BaseException.__str__再次调用,依此类推。修复 #2 通过不BaseException.__str__首先输入来防止此循环,而是使用__repr__根本不触及 args 元组的 which 。