9

下面的代码抛出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,代码运行但不打印任何内容。这没有任何意义,因为根据这篇文章,Python 中的 __str__ 和 __repr__ 之间的区别,省略__str__会调用__repr__,但这里似乎没有发生。

相反,如果我保持对super和 add的调用__str__ = __repr__,那么我会得到预期的输出并且没有递归。

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

4

3 回答 3

4

不要将selfto__init__作为第一个参数。这导致了递归。

它应该是:

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

递归是因为

>>> print Exception("Abc")
Abc

Exception打印第一个参数。FileError因此,当您初始化ie的基类时Exceptionself它继承__str__自它的父级,它打印第一个参数(希望您在语句中看到递归).. 因此您得到无限递归。

__str__ = __repr__覆盖继承__str__并减轻无限递归。

于 2014-01-27T21:45:14.767 回答
4

此行不正确:

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

您需要传入selfsuper()不再作为__init__. 所以它需要是:

super( FileError, self ).__init__( *a, **k )
于 2014-01-27T21:45:39.023 回答
4

您的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__通常打印 args 元组(将使用repr),但当它包含单个参数时,它会打印该str()单个参数的 。

这再次调用BaseException.__str__,依此类推。Fix #2 通过不BaseException.__str__首先输入来防止这个循环,而是使用你的__repr__which 根本不接触 args 元组。

于 2014-01-27T21:52:10.603 回答