web-dev-qa-db-ja.com

「with」ステートメントを終了または終了しますか?

特定の条件下でwithステートメントを終了したいだけです。

with open(path) as f:
    print 'before condition'
    if <condition>: break #syntax error!
    print 'after condition'

もちろん、上記は機能しません。これを行う方法はありますか? (条件を反転できることはわかっています:if not <condition>: print 'after condition'-上記のような方法はありますか?)

33
jmilloy

最適な方法は、関数にカプセル化し、returnを使用することです。

def do_it():
    with open(path) as f:
        print 'before condition'
        if <condition>:
            return
        print 'after condition'
37
Trevor

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'

このセットアップの利点

  • withwithのみを使用します。意味的に誤解を招く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でラップするだけでいいのです!

このセットアップの欠点

  • 実際には「break」ステートメントを使用しません。すべてを獲得することはできません;)
58
Orez

ロジックを再構築する必要があると思います。

with open(path) as f:
    print 'before condition checked'
    if not <condition>:
        print 'after condition checked'
6
K. Brafford

breakはループ内でのみ発生するため、オプションはwith内で次のように制限されます。

  • return( "with" +関連するステートメントを関数内に置く)
  • 終了(プログラムからの保釈-おそらく理想的ではない)
  • 例外(「with」内で例外を生成、以下をキャッチ)

関数を持ち、returnを使用することは、おそらく関数内でwithと関連するステートメント(および他の何も)を分離できる場合、おそらく最もクリーンで簡単なソリューションです。

それ以外の場合は、必要に応じてwith内で例外を生成し、withのすぐ下または外側をキャッチして、残りのコードを続行します。

更新:OPが以下のコメントで示唆しているように(おそらく頬に緊張している?)withステートメントをループ内にラップしてbreakを動作させることもできます-意味的に誤解を招くかもしれませんが。そのため、実用的なソリューションではありますが、おそらく推奨されるものではありません。

5
Levon

これは古くからの質問ですが、これは便利な「壊れやすいスコープ」イディオムのアプリケーションです。 withステートメントを内部に埋め込むだけです:

for _ in (True,):
    with open(path) as f:
        print 'before condition'
        if <condition>: break
        print 'after condition'

このイディオムは、「ループ」を作成し、条件付きで分割できるスコープ内にコードのブロックを囲むという唯一の目的のために、常に1回だけ実行されます。 OPの場合、囲まれるのはコンテキストマネージャの呼び出しでしたが、条件付きエスケープを必要とする可能性のあるステートメントのバインドされたシーケンスである可能性があります。

受け入れられた答えは問題ありませんが、このテクニックは関数を作成する必要なく同じことを行います。これは常に便利または望ましいとは限りません。

3
user2137858
f = open("somefile","r")
for line in f.readlines():
       if somecondition: break;
f.close()

ループから抜け出すことができるとは思わない...ループを使う必要がある...

[編集]または他の人が言及した関数メソッドを実行する

2
Joran Beasley

この目的のための関数__exit__()が存在します。構文は次のとおりです。

with VAR = EXPR:
  try:
    BLOCK
  finally:
    VAR.__exit__()
2
Nimbal Rahul

略記スニペットとして:

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
1
ARtnaMed

関数内にすべてを置くことができ、条件が真の場合にreturnを呼び出します。

1
YuriAlbuquerque