最近、Python の with ステートメントで奇妙な動作に遭遇しました。__exit__Python のコンテキスト マネージャーを使用してメソッドの構成変更をロールバックするコードがあります。manager は、return Falseの finally ブロックに値を持っていました__exit__。次のコードでケースを分離しました - 唯一の違いは return ステートメントのインデントにあります:
class Manager1(object):
def release(self):
pass # Implementation not important
def rollback(self):
# Rollback fails throwing an exception:
raise Exception("A failure")
def __enter__(self):
print "ENTER1"
def __exit__(self, exc_type, exc_val, exc_tb):
print "EXIT1"
try:
self.rollback()
finally:
self.release()
return False # The only difference here!
class Manager2(object):
def release(self):
pass # Implementation not important
def rollback(self):
# Rollback fails throwing an exception:
raise Exception("A failure")
def __enter__(self):
print "ENTER2"
def __exit__(self, exc_type, exc_val, exc_tb):
print "EXIT2"
try:
self.rollback()
finally:
self.release()
return False # The only difference here!
上記のコードでは、ロールバックは例外で失敗します。私の質問は、なぜManager1が とは異なる動作をするかということですManager2。例外は with-statement の外側ではスローされずManager1、なぜ の終了時に例外がスローされるのかManager2。
with Manager1() as m:
pass # The Exception is NOT thrown on exit here
with Manager2() as m:
pass # The Exception IS thrown on exit here
のドキュメントに__exit__よると:
例外が提供され、メソッドが例外を抑制したい場合 (つまり、例外が伝播されないようにしたい場合)、真の値を返す必要があります。それ以外の場合、例外はこのメソッドの終了時に通常どおり処理されます。
私の意見では、どちらの場合も出口は True を返さないため、両方の場合で例外を抑制すべきではありません。ただし、Manager1 ではそうです。誰もそれを説明できますか?
Python 2.7.6 を使用しています。