特定の条件下でwith
ステートメントを終了したいだけです。
with open(path) as f:
print 'before condition'
if <condition>: break #syntax error!
print 'after condition'
もちろん、上記は機能しません。これを行う方法はありますか? (条件を反転できることはわかっています:if not <condition>: print 'after condition'
-上記のような方法はありますか?)
最適な方法は、関数にカプセル化し、return
を使用することです。
def do_it():
with open(path) as f:
print 'before condition'
if <condition>:
return
print 'after condition'
with
で問題が発生しましたか?問題にさらにwith
- ableオブジェクトを投げてください!
class fragile(object):
class Break(Exception):
"""Break out of the with statement"""
def __init__(self, value):
self.value = value
def __enter__(self):
return self.value.__enter__()
def __exit__(self, etype, value, traceback):
error = self.value.__exit__(etype, value, traceback)
if etype == self.Break:
return True
return error
with
を使用する式をfragile
でラップし、raise fragile.Break
いつでも抜け出すために!
with fragile(open(path)) as f:
print 'before condition'
if condition:
raise fragile.Break
print 'after condition'
with
とwith
のみを使用します。意味的に誤解を招く1回実行の「ループ」または狭い専門の関数で関数をラップせず、with
の後に余分なエラー処理を強制しません。ネスレ!
with fragile(open(path1)) as f:
with fragile(open(path2)) as g:
print f.read()
print g.read()
raise fragile.Break
print "This wont happen"
print "This will though!"
このように、両方を壊したい場合、外側のwith
をラップする新しい関数を作成する必要はありません。
fragile
でラップするだけでいいのです!ロジックを再構築する必要があると思います。
with open(path) as f:
print 'before condition checked'
if not <condition>:
print 'after condition checked'
break
はループ内でのみ発生するため、オプションはwith
内で次のように制限されます。
関数を持ち、return
を使用することは、おそらく関数内でwith
と関連するステートメント(および他の何も)を分離できる場合、おそらく最もクリーンで簡単なソリューションです。
それ以外の場合は、必要に応じてwith
内で例外を生成し、with
のすぐ下または外側をキャッチして、残りのコードを続行します。
更新:OPが以下のコメントで示唆しているように(おそらく頬に緊張している?)with
ステートメントをループ内にラップしてbreak
を動作させることもできます-意味的に誤解を招くかもしれませんが。そのため、実用的なソリューションではありますが、おそらく推奨されるものではありません。
これは古くからの質問ですが、これは便利な「壊れやすいスコープ」イディオムのアプリケーションです。 with
ステートメントを内部に埋め込むだけです:
for _ in (True,):
with open(path) as f:
print 'before condition'
if <condition>: break
print 'after condition'
このイディオムは、「ループ」を作成し、条件付きで分割できるスコープ内にコードのブロックを囲むという唯一の目的のために、常に1回だけ実行されます。 OPの場合、囲まれるのはコンテキストマネージャの呼び出しでしたが、条件付きエスケープを必要とする可能性のあるステートメントのバインドされたシーケンスである可能性があります。
受け入れられた答えは問題ありませんが、このテクニックは関数を作成する必要なく同じことを行います。これは常に便利または望ましいとは限りません。
f = open("somefile","r")
for line in f.readlines():
if somecondition: break;
f.close()
ループから抜け出すことができるとは思わない...ループを使う必要がある...
[編集]または他の人が言及した関数メソッドを実行する
この目的のための関数__exit__()
が存在します。構文は次のとおりです。
with VAR = EXPR:
try:
BLOCK
finally:
VAR.__exit__()
略記スニペットとして:
class a:
def __enter__(self):
print 'enter'
def __exit__(self ,type, value, traceback):
print 'exit'
for i in [1]:
with a():
print("before")
break
print("after")
...
enter
before
exit
関数内にすべてを置くことができ、条件が真の場合にreturnを呼び出します。