複数のループから抜け出す方法は?


481

次のコードがあると(動作しません):

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok.lower() == "y": break 2 #this doesn't work :(
        if ok.lower() == "n": break
    #do more processing with menus and stuff

これを機能させる方法はありますか?または、入力ループから抜け出すために1つのチェックを行ってから、ユーザーが満足している場合は、さらに制限された外側のループをチェックしてすべてをまとめて抜け出しますか?


87
なぜPythonは 'break(n)'を持たないのですか。ここで、nはブレークアウトしたいレベルの数です。
ネイサン

2
goto多くのループの奥深くにいる場合、C ++はここで素晴らしい
ドレイクジョンソン

回答:


512

私の最初の本能は、ネストされたループを関数にリファクタリングし、それを使用returnしてブレークアウトすることです。


3
これは別の考えでした。get_input_yn()関数は他の場所でも役立つので、私は確信しています。
Matthew Scharley、2008年

96
この特定のケースでは同意されていますが、「ループがネストされている場合、どうすればよいですか」という一般的なケースでは、リファクタリングが意味をなさない場合があります。
quick_dry 2008年

returnを使用する代わりに、yieldする必要がある場合は、例外を使用する方が簡単な場合がありますが、そのような場合はおそらくitertools.islice()を使用する必要があります。
ロバートキング

5
通常、内側のループを独自のメソッドにリファクタリングできます。続行する場合はtrueを返し、外側のループを解除する場合はfalseを返します。while condition1:/ MyLoop2(params)でない場合:中断します。代替方法は、両方のレベルでテストされるブールフラグを設定することです。more = True / while condition1以上:/ while condition2以上:/ if stopCondition:more = False / break / ...
ToolmakerSteve

7
使用するよう努力することreturnが正しいアプローチであることに同意します。そして、その理由は、Zen of Pythonによると、「ネストするよりフラットの方が良い」ということです。ここには3つのレベルのネストがあります。それが邪魔になり始めたら、ネストを減らすか、少なくともネスト全体を独自の関数に抽出する必要があります。
Lutz Prechelt 2014

240

短い別のアプローチを次に示します。不利な点は、外側のループのみを切断できることですが、それが必要な場合もあります。

for a in xrange(10):
    for b in xrange(20):
        if something(a, b):
            # Break the inner loop...
            break
    else:
        # Continue if the inner loop wasn't broken.
        continue
    # Inner loop was broken, break the outer.
    break

これは、for / else構文を使用して説明されています:なぜPythonはforループとwhileループの後に 'else'を使用するのですか?

重要な洞察:外側のループが常に壊れているように見えるだけですしかし、内側のループが壊れなければ、外側のループも壊れません。

ここでのcontinueステートメントは魔法です。これはfor-else句にあります。定義により何の内側のブレークがない場合はどうなります。そのような状況でcontinueは、外側のブレークをきちんと回避します。


6
@eugeneyどうして?最初のブレークは内側のループから抜け出します。
Navin、2014年

5
@eugeney何かが足りないようです。例を投稿できますか?
Navin、2014年

4
続行する前に移動できる@Mingliang。
Baldrickk 2017

1
レイモンドヘッティンガーのビデオyoutu.be/OSGv2VnC0go?t=971からこれを入手し、forループに添付されている「else」ステートメントを「no_break」として読んでください。理解しやすくなります。
アンバリーシュ、

2
これは賢いです。:-)しかし、簡単ではありません。率直に言って、ラベル付きのbreakまたはbreak(n)をPythonから除外するための引数には確信が持てません。回避策はさらに複雑になります。
rfportilla

148

PEP 3136は、ラベル付きの中断/継続を提案しています。「この機能を必要とするほど複雑なコードは非常にまれである」ため、Guido はこれを拒否しました。ただし、PEPはいくつかの回避策(例外テクニックなど)について言及していますが、Guidoは、ほとんどの場合、returnを使用するようにリファクタリングする方が簡単だと感じています。


73
return通常、refactor / がbreak 2適していますが、単純な簡潔な「」ステートメントが意味をなさない場合がかなりあります。また、refactor / returnはに対して同じようには機能しませんcontinue。これらの場合、数値のブレークアンドコンティニューは、小さな関数にリファクタリングしたり、例外を発生させたり、各ネストレベルでフラグを設定してフラグを設定したりする複雑なロジックよりも、追跡が簡単で雑然としません。グイドがそれを拒否したのは残念だ。
James Haigh 2013

10
break; breakいいだろう。
PyRulez 2013

5
@Jeyekomon問題は、これが問題になるために3つ以上のネストされたループを必要としないことです。2つのネストされたループはかなり一般的です
Jon

6
「この機能を必要とするほど複雑なコードは非常にまれです」。しかし、これほど複雑なコードを使用する場合、breakすべてのループを手動で転送する必要があるため、ラベル付けされたループがないため、さらに複雑になります。愚か。
BallpointBen 2018

3
どうやら、私は5分間しか投稿を編集できません(それは6でした)。それで、これが私の編集された投稿です:私の2セント:Perlは、break(ただし「最後」と呼びます)および「次へ」というラベルを付けて、直接次の反復に進みます。それは決して珍しいことではありません-私はそれをいつも使用しています。私はPythonを初めて使用するので、すでにPythonが必要です。また、番号付きブレークはリファクタリングにとって恐ろしいものになります。ブレークアウトしたいループにラベルを付けてから、ブレーク<ラベル>を使用して、どのループから抜け出したいかを明示的に示します。
John Deighan

119

まず、通常のロジックが役立ちます。

何らかの理由で終了条件を解決できない場合、例外はフォールバック計画です。

class GetOutOfLoop( Exception ):
    pass

try:
    done= False
    while not done:
        isok= False
        while not (done or isok):
            ok = get_input("Is this ok? (y/n)")
            if ok in ("y", "Y") or ok in ("n", "N") : 
                done= True # probably better
                raise GetOutOfLoop
        # other stuff
except GetOutOfLoop:
    pass

この特定の例では、例外は必要ない場合があります。

一方、文字モードアプリケーションでは、「Y」、「N」、「Q」のオプションがよくあります。「Q」オプションの場合は、すぐに終了する必要があります。それはより例外的です。


4
真剣に、例外は非常に安価であり、慣用的なpythonはそれらの多くを使用します。また、カスタムのものを定義してスローすることも非常に簡単です。
グレッグリンド

13
面白いアイデア。私はそれを愛するか、それを憎むかについて引き裂かれています。
Craig McQueen

8
このソリューションは、2つのバリエーションを別々に表示する場合に、より役立ちます。(1)フラグ()を使用するdone。(2)例外を発生させます。それらを1つのソリューションにマージすると、複雑に見えます。将来の読者のために:を含むすべての行を使用するかdone、ORを定義しGetOutOfLoop(Exception)、それを例外として発生させます。
ToolmakerSteve、

4
一般に、例外以外の目的でtryブロックを使用することは非常に困難です。Tryブロックは、エラー処理用に特別に設計されており、奇妙な制御フローに使用することは、文体的にはあまり良くありません。
nobillygreen 2013

3
@ tommy.carstensenそれはナンセンスです。新しい例外サブクラスを定義し、それを発生させ(回答に示されているように)、カスタムメッセージをExceptionコンストラクターに渡すこと(例raise Exception('bla bla bla'):)は、Python 2とPython 3の両方で有効です。私たちのexceptキャッチするブロックのすべての例外を、私たちはループを終了するために使用しているだけで特別な例外。私たちがあなたの提案した方法で行動し、コードのバグが原因で予期しない例外が発生した場合、意図的にループを終了したのと同じように誤って処理されます。
Mark Amery

54

通常、関数へのリファクタリングがこの種の状況に最適なアプローチであることに同意する傾向があります、ネストされたループから抜け出す必要がある場合のために、@ S.Lottが説明した例外発生アプローチの興味深いバリアントを次に示します。Pythonのwithステートメントを使用して、例外の発生を少し見栄えよくします。新しいコンテキストマネージャを定義します(これを行うのは一度だけです)。

from contextlib import contextmanager
@contextmanager
def nested_break():
    class NestedBreakException(Exception):
        pass
    try:
        yield NestedBreakException
    except NestedBreakException:
        pass

これで、このコンテキストマネージャを次のように使用できます。

with nested_break() as mylabel:
    while True:
        print "current state"
        while True:
            ok = raw_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": raise mylabel
            if ok == "n" or ok == "N": break
        print "more processing"

利点:(1)少しすっきりしている(明示的なtry-exceptブロックがない)、(2)をException使用するたびにカスタムビルドのサブクラスを取得するnested_breakException毎回独自のサブクラスを宣言する必要はありません。


40

まず、入力を取得して検証するプロセスを関数にすることも検討できます。その関数内では、値が正しい場合は単に値を返し、正しくない場合はwhileループで回転し続けることができます。これにより、本質的に、解決した問題が取り除かれ、通常、より一般的なケース(複数のループから抜け出す)に適用できます。この構造をコードで絶対に維持する必要があり、簿記のブール値を処理したくない場合は...

次の方法でgotoを使用することもできます(ここからエイプリルフールモジュールを使用)。

#import the stuff
from goto import goto, label

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": goto .breakall
        if ok == "n" or ok == "N": break
    #do more processing with menus and stuff
label .breakall

「gotoは使用しないでください」などのことはわかっていますが、このような奇妙なケースではうまく機能します。


1
それがINTERCALのCOME FROMコマンドのようなものである場合、何も
1800 INFORMATION

3
私はジョークが好きですが、スタックオーバーフローのポイントは良いコードを宣伝することなので、反対票を投じる必要があります:(
Christian Oudard

13
これは、優れたコードとして認定するための、クリーンで読みやすいソリューションだと思うので、投票します。:)
JTハーレー

1
@JTHurleyいいえ、これはクリーンで読み取り可能ではありません。つまり、この例ではクリーンで読みやすいように見えるかもしれませんが、実際のシナリオではgotoが聖なる混乱を作成します。(また、これはすごいアンチパイソンです...)
Alois Mahdal 2015

2
gotoは悪い担当者になりました。プロのコーダーなら、私の意見ではそれを適切に処理できるはずです。
アルバートレンショー

33

「ループブレーカー」として使用する新しい変数を導入します。最初に何か(False、0など)を割り当て、次に外側のループ内で、そこから抜ける前に、値を別の何か(True、1、...)に変更します。ループが終了したら、「親」ループでその値を確認します。実演させてください:

breaker = False #our mighty loop exiter!
while True:
    while True:
        if conditionMet:
            #insert code here...
            breaker = True 
            break
    if breaker: # the interesting part!
        break   # <--- !

無限ループがある場合、これが唯一の方法です。他のループの実行は本当にずっと速いです。これは、ネストされたループが多数ある場合にも機能します。すべてまたはいくつかを終了できます。無限の可能性!これが役に立てば幸い!


22

関数にリファクタリングせずに複数のネストされたループから抜け出すには、組み込みのStopIteration例外を使用して「シミュレートされたgotoステートメント」を利用します

try:
    for outer in range(100):
        for inner in range(100):
            if break_early():
                raise StopIteration

except StopIteration: pass

ネストされたループから抜け出すためのgotoステートメントの使用に関するこの説明を参照してください。


1
これは、例外を処理する独自のクラスを作成するよりもはるかに見栄えがよく、見た目もすっきりしています。これをしてはいけない理由はありますか?
mgjk

実際、StopIterationはジェネレーターに使用されていますが、通常、キャッチされていないStopIteration例外はありません。したがって、それは良い解決策のように見えますが、とにかく新しい例外を作成するのに間違いはありません。
コワルスキー

1
私にとって最良かつ最も簡単なソリューション
Alexandre Huat

16

keeplooping=True
while keeplooping:
    #Do Stuff
    while keeplooping:
          #do some other stuff
          if finisheddoingstuff(): keeplooping=False

またはそのようなもの。内側のループで変数を設定し、内側のループが終了した直後に外側のループで変数をチェックし、必要に応じて中断することができます。エイプリルフールのジョークモジュールを使用することを気にしない限り、私はGOTOメソッドが少し好きです。Pythonicではありませんが、それは理にかなっています。


これは一種のフラグ設定です!
SIslam、2015年

それは非常に良い解決策だと思います。
コワルスキー

13

これは最もきれいな方法ではありませんが、私の意見では、これが最良の方法です。

def loop():
    while True:
    #snip: print out current state
        while True:
            ok = get_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": return
            if ok == "n" or ok == "N": break
        #do more processing with menus and stuff

ここでも再帰を使用して何かを解決できると確信していますが、それがあなたにとって良いオプションであるかどうかはわかりません。


これは私にとって正しい解決策でした。私の使用例はOPのものとは非常に異なっていました。基本的に同じデータを2回ループして順列を見つけていたため、2つのwhileループを分離したくありませんでした。
ブライアンピーターソン

9

そして、2つの条件が真の場合にループを継続しないのはなぜですか?これはよりパイソン的な方法だと思います:

dejaVu = True

while dejaVu:
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y" or ok == "n" or ok == "N":
            dejaVu = False
            break

だよね?

ではごきげんよう。


なぜwhile dejaVu:ですか?とにかく、trueに設定します。
マシューシャーリー

やった!2つのTrue条件で2 つのループをスキップすることを考えていましたが、1つだけで十分です。
MauroAspé12年

2
@MatthewScharleyこれはネストされたループで機能することを示すためだと思います。
ハンドル

@MauroAspéこれは、OPが要求することを正確には行いません。それでも外側のループ全体が実行されますが、目標は、残りのコードを中断すると実行されないことです
yamm

@yamm if not dejaVu: break下部のa で解決できないので、メインループを終了しますか?解決策は求められたものに最も近いと思います。+1
milcak

8

ループロジックを、ループ変数を生成して終了時に返すイテレーターに因数分解します-以下は、画像がなくなるか、配置する場所がなくなるまで、画像を行/列にレイアウトする単純なものです。

def it(rows, cols, images):
    i = 0
    for r in xrange(rows):
        for c in xrange(cols):
            if i >= len(images):
                return
            yield r, c, images[i]
            i += 1 

for r, c, image in it(rows=4, cols=4, images=['a.jpg', 'b.jpg', 'c.jpg']):
    ... do something with r, c, image ...

これには、複雑なループロジックと処理を分割するという利点があります...


3

この場合、他の人からも指摘されているように、機能分解が進むべき道です。Python 3のコード:

def user_confirms():
    while True:
        answer = input("Is this OK? (y/n) ").strip().lower()
        if answer in "yn":
            return answer == "y"

def main():
    while True:
        # do stuff
        if user_confirms():
            break

3

Pythonのwhile ... else構造には隠されたトリックがあり、コードの変更や追加をあまり行わなくても、ダブルブレークをシミュレートできます。基本的に、while条件がfalseの場合、elseブロックがトリガーされます。例外もブロックcontinuebreakトリガーしませんelse。詳細については、「Python whileステートメントのElse句」への回答、またはPythonドキュメントのwhile(v2.7)を参照してください

while True:
    #snip: print out current state
    ok = ""
    while ok != "y" and ok != "n":
        ok = get_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N":
            break    # Breaks out of inner loop, skipping else

    else:
        break        # Breaks out of outer loop

    #do more processing with menus and stuff

唯一の欠点は、二重破壊条件を条件に移動するwhile(またはフラグ変数を追加する)必要があることです。これのバリエーションはforループにも存在し、elseループの完了後にブロックがトリガーされます。


これはダブルブレイクの要件を満たしていないようです。正確に与えられた問題に対しては機能しますが、実際の質問に対しては機能しません。
ダッカロン2016年

@Dakkaronコードを正しく理解しましたか?コードは実際にOPの問題を解決し、リクエストと同様に機能しなくなります。ただし、複数のループから抜け出すことはありませんが、else句を使用して、切れ目を2倍にする必要を置き換えます。
holroy

私の理解では、質問はHow to break out of multiple loops in Python?「それはうまくいかず、何か他のことを試してください」でした。私はそれがOPの正確な例を修正することを知っていますが、彼らの質問には答えません。
ダッカロン2016年

@Dakkaron、コードの下の問題ステートメントを参照してください。私の意見では、それは確かにOPの質問に答えます。
holroy 2016年

2

反復を単一レベルのループに減らす別の方法は、Pythonリファレンスでも指定されているジェネレーターを使用することです。

for i, j in ((i, j) for i in A for j in B):
    print(i , j)
    if (some_condition):
        break

ループのレベルをいくつでもスケールアップできます

欠点は、1つのレベルだけを壊すことができなくなることです。それは全部か無かです。

もう1つの欠点は、whileループでは機能しないことです。私はもともとこの答えをPythonに投稿したかった-すべてのループから「抜け出す」が、残念ながらこれはこのループの複製として閉じられている


1
whileループでも機能します。ジェネレーターをdefとして(yieldを使用して)記述するだけでよく、内包表記としては必要ありません。
Veky

はい、PyConの講演者は、 @ RobertRossneyの承認された回答でさえも本当にPythonicではないが、ジェネレータは複数のループを解く正しい方法であると主張しています。(ビデオ全体を見ることをお勧めします!)
Post169 '19

2

ここに来る理由は、次のように外側のループと内側のループがあったためです。

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

  do some other stuff with x

ご覧のとおり、実際には次のxには移動しませんが、代わりに次のyに移動します。

これを解決するために私が見つけたのは、代わりに配列を2回実行することでした:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

for x in array:
  do some other stuff with x

これはOPの質問の特定のケースであることはわかっていますが、物事をシンプルに保ちながら、誰かが問題について異なる考え方をするのに役立つことを期待して投稿しています。


これはおそらくPythonではありません。配列のタイプは何ですか?おそらくリストしますが、何が含まれていますか?それがintを含んでいても、array.pop(x)はおそらくあなたが望むことをしません。
Veky 2016

それは良い点です。参照したコードが見つかりません。これを読んでいる人のために、array.pop(i)「配列からインデックスiのアイテムを削除して返します。」Pythonのドキュメントに従って。したがって、このコードを期待どおりに機能させるには、配列内の項目xのインデックスを取得する必要があります。期待されることを実行するarray.remove(x)関数もあります。上記の回答を修正して、そのエラーを修正します。array.remove(x)はxの最初のインスタンスのみを削除するため、これは2番目の配列に重複がないことを前提としています。
Nathan Garabedian

わかりました。その場合、break代わりにcontinueを使用するだけで、望みどおりの結果が得られますね。:-)
Veky

ええ、効率と明快さのために、あなたはおそらくこれらの例で続けるのではなくブレークを使いたいでしょう。:)
Nathan Garabedian

2

無限ジェネレーターを使用してみてください。

from itertools import repeat
inputs = (get_input("Is this ok? (y/n)") for _ in repeat(None))
response = (i.lower()=="y" for i in inputs if i.lower() in ("y", "n"))

while True:
    #snip: print out current state
    if next(response):
        break
    #do more processing with menus and stuff

2

関数を使用して:

def myloop():
    for i in range(1,6,1):  # 1st loop
        print('i:',i)
        for j in range(1,11,2):  # 2nd loop
            print('   i, j:' ,i, j)
            for k in range(1,21,4):  # 3rd loop
                print('      i,j,k:', i,j,k)
                if i%3==0 and j%3==0 and k%3==0:
                    return  # getting out of all loops

myloop()

コメントアウトして上記のコードを実行してみてください return同様に。

関数を使用しない場合:

done = False
for i in range(1,6,1):  # 1st loop
    print('i:', i)
    for j in range(1,11,2):  # 2nd loop
        print('   i, j:' ,i, j)
        for k in range(1,21,4):  # 3rd loop
            print('      i,j,k:', i,j,k)
            if i%3==0 and j%3==0 and k%3==0:
                done = True
                break  # breaking from 3rd loop
        if done: break # breaking from 2nd loop
    if done: break     # breaking from 1st loop

ここで、上記のコードを最初から実行し、次にbreak、下から1つずつ含まれる各行をコメント化して実行してみます。


2

複数のループを1つの壊れやすいループに変える簡単な方法は、 numpy.ndindex

for i in range(n):
  for j in range(n):
    val = x[i, j]
    break # still inside the outer loop!

for i, j in np.ndindex(n, n):
  val = x[i, j]
  break # you left the only loop there was!

明示的に値を反復処理できるのではなく、オブジェクトにインデックスを付ける必要がありますが、少なくとも単純なケースでは、提案されているほとんどの回答よりも約2〜20倍単純であるようです。


2
# this version uses a level counter to choose how far to break out

break_levels = 0
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_levels = 1        # how far nested, excluding this break
            break
        if ok == "n" or ok == "N":
            break                   # normal break
    if break_levels:
        break_levels -= 1
        break                       # pop another level
if break_levels:
    break_levels -= 1
    break

# ...and so on

1

関数へのリファクタリングを好まない場合は、おそらく以下のような小さなトリックで十分です

whileループ条件を制御するために1つのbreak_level変数を追加しました

break_level = 0
# while break_level < 3: # if we have another level of nested loop here
while break_level < 2:
    #snip: print out current state
    while break_level < 1:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": break_level = 2 # break 2 level
        if ok == "n" or ok == "N": break_level = 1 # break 1 level

1

変数(たとえば、break_statement)を定義し、2つのブレーク条件が発生したときに変数を別の値に変更し、ifステートメントで使用して2番目のループからブレークすることもできます。

while True:
    break_statement=0
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N": 
            break
        if ok == "y" or ok == "Y": 
            break_statement=1
            break
    if break_statement==1:
        break

良い点ですが、関心のある内部レベルより上の各レベルでは、その変数をスキャンする必要があります。言語にGoTo命令がないこと、パフォーマンスの面で本当に悪いと感じています。
アナトリーアレクセーエフ

1

Pythonの関数はコードの真ん中に作成でき、周囲の変数に透過的にアクセスして読み取りnonlocalまたはglobal書き込み宣言を宣言。

したがって、関数を「壊れやすい制御構造」として使用して、戻りたい場所を定義できます。

def is_prime(number):

    foo = bar = number

    def return_here():
        nonlocal foo, bar
        init_bar = bar
        while foo > 0:
            bar = init_bar
            while bar >= foo:
                if foo*bar == number:
                    return
                bar -= 1
            foo -= 1

    return_here()

    if foo == 1:
        print(number, 'is prime')
    else:
        print(number, '=', bar, '*', foo)

>>> is_prime(67)
67 is prime
>>> is_prime(117)
117 = 13 * 9
>>> is_prime(16)
16 = 4 * 4

1

2つの方法でのソリューション

例:これらの2つの行列は等しい/同じですか?
matrix1とmatrix2は同じサイズ、n、2次元行列です。

最初のソリューション機能せず

same_matrices = True
inner_loop_broken_once = False
n = len(matrix1)

for i in range(n):
    for j in range(n):

        if matrix1[i][j] != matrix2[i][j]:
            same_matrices = False
            inner_loop_broken_once = True
            break

    if inner_loop_broken_once:
        break

第二の溶液機能を持つ
。これは、私の場合のための最終的な解決策であります

def are_two_matrices_the_same (matrix1, matrix2):
    n = len(matrix1)
    for i in range(n):
        for j in range(n):
            if matrix1[i][j] != matrix2[i][j]:
                return False
    return True

ごきげんよう!


1
# this version breaks up to a certain label

break_label = None
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_label = "outer"   # specify label to break to
            break
        if ok == "n" or ok == "N":
            break
    if break_label:
        if break_label != "inner":
            break                   # propagate up
        break_label = None          # we have arrived!
if break_label:
    if break_label != "outer":
        break                       # propagate up
    break_label = None              # we have arrived!

#do more processing with menus and stuff

0

うまくいけば、これは役立ちます:

x = True
y = True
while x == True:
    while y == True:
         ok = get_input("Is this ok? (y/n)") 
         if ok == "y" or ok == "Y":
             x,y = False,False #breaks from both loops
         if ok == "n" or ok == "N": 
             break #breaks from just one

0

動作しているように見える実装は次のとおりです。

break_ = False
for i in range(10):
    if break_:
        break
    for j in range(10):
        if j == 3:
            break_ = True
            break
        else:
            print(i, j)

唯一の欠点はbreak_、ループの前に定義する必要があることです。


0

言語レベルからこれを行う方法はありません。一部の言語にはgotoがあり、他の言語には引数を取る中断がありますが、pythonではありません。

最適なオプションは次のとおりです。

  1. 外部ループによってチェックされるフラグを設定するか、外部ループ条件を設定します。

  2. 関数にループを配置し、returnを使用してすべてのループを一度に抜け出します。

  3. ロジックを再構成します。

クレジットは1987年以来プログラマーであるVivek Nagarajanに贈られます


関数の使用

def doMywork(data):
    for i in data:
       for e in i:
         return 

フラグを使用する

is_break = False
for i in data:
   if is_break:
      break # outer loop break
   for e in i:
      is_break = True
      break # inner loop break

-3

以前のものと似ていますが、よりコンパクトです。(ブール値は単なる数値です)

breaker = False #our mighty loop exiter!
while True:
    while True:
        ok = get_input("Is this ok? (y/n)")
        breaker+= (ok.lower() == "y")
        break

    if breaker: # the interesting part!
        break   # <--- !

2
これはかなり醜く見え、前のコードと比較してコードを理解するのが難しくなります。また、それは間違っています。入力が受け入れ可能であるかどうかを実際にチェックするのを怠り、1ループ後に中断します。
エリック

-3

この質問は特定のループに割り込むための標準的な質問になっているので、を使用した例で答えを示したいと思いExceptionます。

multipally looped構文にはbreaking of loopという名前のラベルはありませんが、ユーザー定義の例外を利用して、選択した特定のループに割り込むことができます。基数6の番号付けシステムで4桁までのすべての数値を出力する次の例を考えてみます。

class BreakLoop(Exception):
    def __init__(self, counter):
        Exception.__init__(self, 'Exception 1')
        self.counter = counter

for counter1 in range(6):   # Make it 1000
    try:
        thousand = counter1 * 1000
        for counter2 in range(6):  # Make it 100
            try:
                hundred = counter2 * 100
                for counter3 in range(6): # Make it 10
                    try:
                        ten = counter3 * 10
                        for counter4 in range(6):
                            try:
                                unit = counter4
                                value = thousand + hundred + ten + unit
                                if unit == 4 :
                                    raise BreakLoop(4) # Don't break from loop
                                if ten == 30: 
                                    raise BreakLoop(3) # Break into loop 3
                                if hundred == 500:
                                    raise BreakLoop(2) # Break into loop 2
                                if thousand == 2000:
                                    raise BreakLoop(1) # Break into loop 1

                                print('{:04d}'.format(value))
                            except BreakLoop as bl:
                                if bl.counter != 4:
                                    raise bl
                    except BreakLoop as bl:
                        if bl.counter != 3:
                            raise bl
            except BreakLoop as bl:
                if bl.counter != 2:
                    raise bl
    except BreakLoop as bl:
        pass

出力を出力するとき、単位の位置が4である値を取得することはありません。その場合、BreakLoop(4)同じループで発生し、キャッチされるため、ループから抜けることはありません。同様に、10の場所に3がある場合は常に、を使用して3番目のループに分割しBreakLoop(3)ます。100の場所が5を持っているときはいつでも、2番目のループを使用BreakLoop(2)して分割し、1000の場所が2を持っているときはいつでも、使用して最初のループに分割しますBreakLoop(1)

簡単に言うと、内側のループで(組み込みまたはユーザー定義の)例外を発生させ、制御を再開したい場所からループでそれをキャッチします。すべてのループから抜けたい場合は、すべてのループの外側で例外をキャッチします。(私はこの例を例に示していません)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.