9

次のコードは をスローしRuntimeError: maximum recursion depth exceeded while getting the str of an objectます。無限再帰は 2 つの異なる方法で解決できますが、それぞれの修正が機能する理由が理解できないため、どちらを使用すればよいのか、またはどちらが正しいのかわかりません。

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て追加すると__str__ = __repr__、期待される出力が得られ、再帰はありません。

無限再帰が存在する理由、各変更が無限再帰を解決する理由、およびある修正が他の修正よりも優先される理由を誰かが説明できますか?

4

3 に答える 3

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__これが再び呼び出されます。修正 #2BaseException.__str__は、最初から入力しないことで、このサイクルを防ぎます。代わりに__repr__、args タプルにまったく触れない your を使用します。

于 2014-01-27T21:52:10.603 に答える
4

最初の引数としてselftoを渡さないでください。__init__それが再帰を引き起こしています。

そのはず:

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

再帰が発生する理由

>>> print Exception("Abc")
Abc

Exception最初の引数を出力します。したがって、最初の引数を出力する親から継承するFileErrorieExceptionの基本クラスを初期化すると (ステートメントで再帰が見られることを願っています).. したがって、無限再帰が得られます。self__str__

__str__ = __repr__継承されたものをオーバーライドし__str__、無限再帰を軽減します。

于 2014-01-27T21:45:14.767 に答える
4

この行は正しくありません:

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

に引数として渡す必要がありますが、再度渡す必要selfはありません。したがって、次のようにする必要があります。super()__init__

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