Python:外側のループで次の反復に進む


135

Pythonの外側のループで次の反復に進むための組み込みの方法があるかどうかを知りたいと思いました。たとえば、次のコードを考えます。

for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            continue
    ...block1...

このcontinueステートメントでjjループを終了し、iiループの次の項目に移動する必要があります。このロジックは他の方法で(フラグ変数を設定することで)実装できますが、これを行う簡単な方法はありますか?


11
実際には、Python用のgotoステートメントentrian.com/gotoが存在します。それはエイプリルフールのジョークとしてリリースされました:-)、動作するはずです。
codeape 09/07/12

3
ああ、後藤冗談は使わないで!それは驚くほど賢いですが、コードに入れてしまうと後で悲しくなります。
Ned Batchelder、

回答:


71
for i in ...:
    for j in ...:
        for k in ...:
            if something:
                # continue loop i

一般的なケースでは、複数レベルのループがあり、 break機能しない場合(現在のループのすぐ上のループではなく、上のループの1つを継続したいため)、次のいずれかを実行できます。

エスケープしたいループを関数にリファクタリングする

def inner():
    for j in ...:
        for k in ...:
            if something:
                return


for i in ...:
    inner()

欠点は、以前はスコープ内にあったいくつかの変数をその新しい関数に渡す必要がある場合があることです。それらをパラメーターとして渡すか、オブジェクトのインスタンス変数にするか(意味がある場合は、この関数のために新しいオブジェクトを作成する)、またはグローバル変数、シングルトンなど(ehm、ehm)のいずれかを使用できます。

またはinner、ネストされた関数として定義して、必要なものだけをキャプチャすることもできます(遅いかもしれませんか?)

for i in ...:
    def inner():
        for j in ...:
            for k in ...:
                if something:
                    return
    inner()

例外を使用する

哲学的には、これは例外であり、必要に応じて、構造化プログラミングビルディングブロック(if、for、while)を通るプログラムフローを中断します。

利点は、単一のコードを複数の部分に分割する必要がないことです。これは、Pythonで記述しているときに設計しているある種の計算である場合に適しています。この初期段階で抽象化を導入すると、速度が低下する可能性があります。

このアプローチの悪い点は、インタプリタ/コンパイラの作成者は通常、例外は例外的であると想定し、それに応じて例外を最適化することです。

class ContinueI(Exception):
    pass


continue_i = ContinueI()

for i in ...:
    try:
        for j in ...:
            for k in ...:
                if something:
                    raise continue_i
    except ContinueI:
        continue

このための特別な例外クラスを作成して、他の例外を誤って消してしまうリスクを回避します。

完全に別の何か

私はまだ他の解決策があると確信しています。


2番目のループを別のメソッドに移動することを考えていなかったなんて信じられません。私は遅くなっています
pmccallum

1
私にとって、例外を使用することは、これを達成する良い方法です。@ user7610に同意します-「哲学的に、これは例外です」。
Renato Byrro

古き良きブール変数とIf文?
MrR

OPはそれに対する代替ソリューションを探しています。「このロジックを別の方法で実装できます(フラグ変数を設定することで)[...]」
user7610

149
for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            break
    else:
        ...block1...

Break 内側のループが中断され、block1は実行されません(内側のループが正常に終了した場合にのみ実行されます)。


1
こんにちは、このような他のオプションはありますか?block1で別のforループを実行したいので、私のコードは3レベル深くなります。変な状況。
Sahas

3
私には、別の方法でアプローチするのが最善のforループで何かをしようとしているように聞こえます...
Kimvais

はい。そのため、for..else構造を使用しませんでした。今はまだループが必要ですが、フラグ変数を使用して制御を迂回させます。
Sahas

3
for...else混乱する可能性がありますが、多くの場合、便利な構成です。elseこれは、この文脈では「休憩なし」を意味することを覚えておいてください。
asmeurer 2014年

これはループが2層に限定されているようです。3つのネストされたループを持つコードを更新する必要があります。新しい顧客の要件は、特定の状況下で、最も内側のループが最も外側のループの次の反復を継続する必要があることを意味します。あなたの提案はそのシナリオには当てはまらないと思います。
kasperd

42

他の言語では、ループにラベルを付けて、ラベルを付けたループから抜けることができます。 Python Enhancement Proposal(PEP)3136はこれらをPythonに追加することを提案しましたが、Guidoは拒否しました

ただし、この機能を必要とするほど複雑なコードは非常にまれであるため、これを拒否します。ほとんどの場合、たとえば「return」を使用するなど、クリーンなコードを生成する既存の回避策があります。コードの明快さがreturnの使用を可能にするリファクタリングの影響を受けるいくつかの(まれな)実際のケースがあると私は確信していますが、これは2つの問題によって相殺されます:

  1. 言語に複雑さを永続的に追加しました。これは、すべてのPython実装だけでなく、すべてのソース分析ツール、そしてもちろんその言語のすべてのドキュメントにも影響します。

  2. 機能が適切に使用されるよりも悪用され、コードの明快さの最終的な低下につながると私は予想しています(これ以降に記述されたすべてのPythonコードで測定)。怠惰なプログラマーはいたるところにいます。そして、あなたがそれを知る前に、あなたは理解できないコードの手に信じられないほどの混乱を持っています。

だから、それがあなたが望んでいたものであるなら、あなたは運が悪いのですが、そこには良い選択肢があるので、他の答えの一つを見てください。


4
面白い。ここでグイドに同意します。場合によってはそれはいいことですが、悪用されることもあります。これを実装しないもう1つの理由は、現時点ではCとPythonの間でコードを移植するのが非常に簡単なことです。Pythonが他の言語に欠けている機能を取り上げ始めると、これはより困難になります。たとえば、Pythonのforループでelseステートメントを使用できるという事実を考えてみてください...これにより、他の言語へのコードの移植性が低下します。
eric.frederich 2013

2
すべてのグイドは私たちのBDFLを歓迎します
JnBrymn 14

4
これは適切な反論というよりは真っ赤なものですが、for-else名前付きループよりも動作が複雑で、読みにくく、おそらく乱用されています(完全な間違いではないとしても)。私は別のキーワードを使用したと思いますelse-おそらく何かresumeが良かったのでしょうか?あなたbreakはループに入っており、そのresume直後ですか?
ArtOfWarfare 14

5
これは私を悲しくします。Pythonが好きで嫌いであることが同時に信じられません。とても美しいが、それでもwtf。
jlh 2017

5
@jlhたいてい私にとってwtf。時々私はそれが正当な目的のためではなく、単に違うようになりたいと思うと思います。これはその良い例です。外側のループを頻繁に壊す必要に出くわします。
Rikaelus 2017

14

私はあなたがこのようなことをすることができると思います:

for ii in range(200):
    restart = False
    for jj in range(200, 400):
        ...block0...
        if something:
            restart = True
            break
    if restart:
        continue
    ...block1...

4
-1:OPは、彼らがこのようなことを実行できることを知っていたと明確に述べており、これは受け入れられた回答の厄介なバージョンのように見えます(8か月前にあなたの回答よりも古いため、受け入れられなかっただけではあり得ませんでした。回答)。
ArtOfWarfare 14

10
これまでに見たことがないなら、受け入れられた答えは明確ではありません(そしてforelseそれがどのように機能するかを頭の上で覚えていないほとんどの人でさえも思うと思います)。
asmeurer 2014

3

これを実現する最も簡単な方法の1つは、「続行」を「中断」ステートメントに置き換えることです。

for ii in range(200):
 for jj in range(200, 400):
    ...block0...
    if something:
        break
 ...block1...       

たとえば、次のコードは、それがどのように行われるかを正確に確認する簡単なコードです。

for i in range(10):
    print("doing outer loop")
    print("i=",i)
    for p in range(10):
        print("doing inner loop")
        print("p=",p)
        if p==3:
            print("breaking from inner loop")
            break
    print("doing some code in outer loop")

2

この種の問題に対処する別の方法は、Exception()を使用することです。

for ii in range(200):
    try:
        for jj in range(200, 400):
            ...block0...
            if something:
                raise Exception()
    except Exception:
        continue
    ...block1...

例えば:

for n in range(1,4):
    for m in range(1,4):
        print n,'-',m

結果:

    1-1
    1-2
    1-3
    2-1
    2-2
    2-3
    3-1
    3-2
    3-3

m = 3の場合、mループから外側のnループにジャンプしたいとします。

for n in range(1,4):
    try:
        for m in range(1,4):
            if m == 3:
                raise Exception()            
            print n,'-',m
    except Exception:
        continue

結果:

    1-1
    1-2
    2-1
    2-2
    3-1
    3-2

参照リンク:http : //www.programming-idioms.org/idiom/42/continue-outer-loop/1264/python


1

何かを見つけてから、内部の反復を停止します。私はフラグシステムを使用しています。

for l in f:
    flag = True
    for e in r:
        if flag==False:continue
        if somecondition:
            do_something()
            flag=False

なぜあなたのソリューションが反対票を投じられたのかはわかりません。誰かが基本的にまったく同じものを投稿し、10回賛成票を得た
Locane

私はstackoverflowにあまり運が悪い。
Esther

1
たぶん、ここに投稿されたものとまったく同じものがあるのか​​もしれませんが、おそらくFalse:continue...異常なフォーマットです。指数関数が標準である「自然な」システムではよくあることですが、SOで幸運を数回獲得するだけで、かなりの評判ポイントを獲得できます。とにかく、私の「最良の」答えは通常、最も人気のないものです。
user7610

0

私はちょうどこのようなことをしました。これに対する私の解決策は、内部forループをリスト内包に置き換えることでした。

for ii in range(200):
    done = any([op(ii, jj) for jj in range(200, 400)])
    ...block0...
    if done:
        continue
    ...block1...

ここで、opはiiとjjの組み合わせに作用するブール演算子です。私の場合、いずれかの操作がtrueを返した場合、私は完了しました。

これはコードを関数に分解することと実際にはそれほど違いはありませんが、ブール演算子のリストに対して「any」演算子を使用して論理ORを実行し、1行ですべてのロジックを実行することは興味深いと思いました。また、関数呼び出しを回避します。

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