なぜPythonはforループとwhileループの後に 'else'を使用するのですか?


481

この構成がどのように機能するか理解しています:

for i in range(10):
    print(i)

    if i == 9:
        print("Too big - I'm giving up!")
        break;
else:
    print("Completed successfully")

しかしelse、ここでキーワードとして使用されている理由がわかりません。問題のコードは、forブロックが完了しない場合にのみ実行されることを示唆しているためです。どう考えても、私の脳はfor発言からelseブロックまでシームレスに進むことができません。私にとって、continueまたはcontinuewithもっと理にかなっているでしょう(そして私はそれをそのように読むように自分を訓練しようとしています)。

Pythonのコーダーがこの構成を頭の中で(または、必要に応じて)読み上げる方法を知りたいと思います。おそらく、そのようなコードブロックをより簡単に解読できるものがないのでしょうか。


26
あなたはそれを頭の中で「それから」に翻訳したいと思うかもしれません。
Marcin

63
Zen of Pythonの重要な行を忘れないでください。
ダニエルローズマン

51
私の頭の中では、それを「壊れないのなら」に翻訳します。また、「I've found it」ループでbreakelse
頻繁に

29
多くの人が本当の疑問を持っているのは、「forループと、ループの後にfor ... else foo()置くだけの違いは何foo()ですか?」だと思います。そしてその答えは、ループにaが含まれている場合にのみ、それらの動作が異なるということですbreak(以下で詳細に説明します)。
Sam Kauffman、

10
pythonのセミコロン...目が痛い..構文的に正しいとしても、そうすることはお
勧め

回答:


278

熟練したPythonプログラマにとっても、これは奇妙な構成です。forループと組み合わせて使用​​する場合、基本的には「イテラブル内のアイテムを検索します。見つからなかった場合は...」を意味します。のように:

found_obj = None
for obj in objects:
    if obj.key == search_key:
        found_obj = obj
        break
else:
    print('No object found.')

しかし、この構造が表示されたときはいつでも、検索を関数にカプセル化することをお勧めします。

def find_obj(search_key):
    for obj in objects:
        if obj.key == search_key:
            return obj

または、リスト内包表記を使用します。

matching_objs = [o for o in objects if o.key == search_key]
if matching_objs:
    print('Found {}'.format(matching_objs[0]))
else:
    print('No object found.')

他の2つのバージョンと意味的には同等ではありませんが、リスト全体を反復するかどうかに関係なく、パフォーマンスが重要ではないコードで十分に機能します。他の人は同意しないかもしれませんが、私は個人的には、for-elseまたはwhile-elseブロックを製品コードで使用することは避けます。

[Python-ideas] for ... elseスレッドの概要も参照してください


50
リスト内包表記は間違っています。あなたはのように、単一の項目を探しているならforループの例、および発電表現/リストの内包表記を使用したい場合、あなたはしたいnext((o for o in objects if o.key == search_key), None)かでそれをラップtry/ exceptとするのではなく、デフォルト値を使用していませんif/ else
agf

4
ランス・ヘルステンの答えと同様に、実際にはfor/else構成を使用した方がよい場合があります。
andrean 14

5
乾杯。とelseペアになったひどくインデントされたファイルがあり、forそれが合法であるとは思いませんでした。
maxywb 2014年

3
forループが最もわかりやすい構成要素であると思います。
Miles Rout 2014

14
breakこの例のようにステートメントが明示的に実行されない限り、forループに値が含まれている場合でも、else句が実行されることは言及する価値があります。上記のドキュメントから:「else句には別の認識されている問題があります。breakループ内にelse句がない場合、句は機能的に冗長です。」例for x in [1, 2, 3]:\n print x\n else:\n print 'this executes due to no break'
dhackner 2014

587

一般的な構成は、何かが見つかるまでループを実行し、ループから抜け出すことです。問題は、ループから抜け出した場合、またはループが終了した場合に、どのケースが発生したかを判別する必要があることです。1つの方法は、フラグまたはストア変数を作成して、ループがどのように終了したかを確認するための2番目のテストを実行することです。

たとえば、フラグアイテムが見つかるまでリストを検索して各アイテムを処理し、その後処理を停止する必要があるとします。フラグアイテムがない場合は、例外を発生させる必要があります。

あなたが持っているPython for... else構成を使用する

for i in mylist:
    if i == theflag:
        break
    process(i)
else:
    raise ValueError("List argument missing terminal flag.")

これを、この構文糖を使用しないメソッドと比較してください。

flagfound = False
for i in mylist:
    if i == theflag:
        flagfound = True
        break
    process(i)

if not flagfound:
    raise ValueError("List argument missing terminal flag.")

最初のケースでraiseは、は動作するforループにしっかりとバインドされています。2番目の場合、バインディングはそれほど強くなく、メンテナンス中にエラーが発生する可能性があります。


69
これは、著者がfor-elseについて何を本当に得ていないという選択された回答よりも優れています。
erikbwork 2014

17
この構文上の砂糖はあなたのプロジェクトの歯を腐らせるかもしれないと私は言わなければなりません。これは本にはなりませんPython: the good parts
ボートコーダー2015

1
あなたの例でprocess(i)は、すべてのアイテムに対して、それ自体ではなく、mylist以前に厳密に発生することを確認できますか?それは意図されたものですか?theflagtheflag
bli

4
processに到達iする前にリストに存在する各theflag要素で実行され、の後のリストの要素ではtheflag実行されず、では実行されませんtheflag
ランスヘルステン2015年

1
elseステートメントは、
イテラブルに

173

レイモンドヘッティンガーによる優れたプレゼンテーションで、「コードを美しく慣用的なPython変換する」というタイトルで、for ... else構成の歴史について簡単に説明しています。関連セクションは、15:50に開始して約3分間続く「ループ内の複数の出口点の識別」です。ここに重要な点があります:

  • このfor ... else構造は、特定のGOTOユースケースの代わりとしてDonald Knuthによって考案されました。
  • 再利用elseのキーワードは、「それはクヌースを使用したものだ、と人々は、その時点で、知っていた、すべての[ので意味を成していたfor文]埋め込まれていたifGOTOの下に、彼らは予想しましたelse;」
  • 後から見ると、「ノーブレーク」(または「ノーブレーク」)と呼ばれるはずでしたが、混乱することはありません。*

したがって、「なぜこのキーワードを変更しないのか」という質問の場合、次に、Cat Plus Plusがおそらく最も正確な答えを出しました。この時点では、既存のコードを破壊するので実用的ではありません。しかし、あなたが本当に質問している質問が、なぜelse最初に再利用されたのかである場合、まあ、明らかにそれは当時は良い考えのように思われました。

個人的には、ループ内にあると一目で誤解される可能性がある# no break場所にインラインでコメントする妥協案が好きelseです。それはかなり明確で簡潔です。このオプションは、ビョルンが回答の最後にリンクした要約で簡単な言及を得ます:

完全を期すために、構文を少し変更するだけで、この構文を必要とするプログラマーがすぐにそれを使用できるようになることを述べておきます。

for item in sequence:
    process(item)
else:  # no break
    suite

*ビデオのその部分からのボーナス引用:「ラムダのmakefunctionを呼び出した場合と同じように、「ラムダは何をするのですか?」


33

彼らは言語に新しいキーワードを導入したくなかったからです。それぞれが識別子を盗み、下位互換性の問題を引き起こすため、通常は最後の手段です。


2
そのようなfinally場合には、より良い選択だったでしょう。この構成が導入されたとき、finallyキーワードはまだ存在していませんでしたか?
Ponkadoodle 2014年

26
@Wallacoloo finallyは、ブロックがループの後に常に実行されることを意味するため、あまり良くありません(ループの後に実行するコードを配置するだけでは冗長になるため)。
Cat Plus Plus

またfinally、else句がcontinueforループで使用されている場合にも実行されるため、これは不可能です。
pepr 2014

6
@pepr else句の実行はcontinueドキュメントテストコード)の影響を受けません
Air

@AirThomas:+1。あなたが正しいです。elseときにのみ実行されcontinue、最後の反復の一つでした。
pepr 2014年

33

簡単にするために、そのように考えることができます。

  • ループ内でbreakコマンドに遭遇した場合forelseパーツは呼び出されません。
  • ループ内でbreakコマンドが検出されない場合forelseパーツが呼び出されます。

つまり、forループの反復がで「壊れていない」break場合、elseパーツが呼び出されます。


elseループの本体で例外が発生した場合も、ブロックは実行されません。
Amal K

17

for / elseの動作を「取得」するために見つけた最も簡単な方法は、さらに重要なことに、いつそれを使用するかは、breakステートメントがどこにジャンプするかに集中することでした。For / elseコンストラクトは単一のブロックです。ブレークはブロックの外にジャンプするため、else句の「上」にジャンプします。else句の内容が単にfor句の後に続く場合は、飛び越されることはないため、同等のロジックをifに入れて提供する必要があります。これは以前にも言われましたが、これらの言葉では完全ではないので、他の誰かを助けるかもしれません。次のコードを実行してみてください。私は明確にするために「休憩なし」のコメントを心から支持しています。

for a in range(3):
    print(a)
    if a==4: # change value to force break or not
        break
else: #no break  +10 for whoever thought of this decoration
    print('for completed OK')

print('statement after for loop')

「ブレイクはブロックから飛び出し、else句を「飛び越え」ます」 -これは「for:/ 」を取得する方法としては役立つかもしれelse:ませんが、キーワードが存在することの正当性を実際に提供するものではありませんelse。ここで与えられたフレーミングを考えると、then:はるかに自然なようです。(他の回答で示されているように、選択される理由がありelseます-それらはここでは提供されていません。)
Mark Amery 2018

16

ドキュメンテーションは他の素晴らしい説明があると思い ます続けてください

[...]ループがリストを使い果たして(forで)終了したとき、または条件がfalseになったときに(whileで)実行されますが、breakステートメントによってループが終了したときは実行されません。

ソース:Python 2ドキュメント:制御フローのチュートリアル


13

私はそれを次のように読みます:

ループを実行する条件がまだある場合は、何かを行い、そうでない場合は別のことを行います。


それは間違っていますがあなたの静止状態は役に立ちます(+1)-それは人間です;-)
ウルフ

-1; このfor:/の発音はelse:else:が常にループの後に実行されるように聞こえますが、そうではありません。
マークアメリー2018

11

技術的な部分についてはかなりの回答が得られたので、私のコメントは、このリサイクルを生み出す混乱と関連しています。キーワードます。

Pythonは非常に雄弁なプログラミング言語であるため、キーワードの誤用はより悪名高いです。else「あなたはこれを行うことができない場合はそれを行うこと(他)、」キーワードは完全に、決定木の流れの一部を説明しています。それは暗示されていますは私たち自身の言語でれています。

代わりに、このキーワードをwhileand forステートメントで使用すると混乱が生じます。理由は、プログラマーとしての私たちのキャリアは、elseステートメントが意思決定ツリー内にあることを教えてくれました。その論理的範囲、ラッパー条件付きでフォローへのパスを返します。一方、ループステートメントには、何かに到達するという比喩的な明示的な目標があります。プロセスの継続的な反復後に目標が達成されます。

if / else たどる経路を示します。ループは、「目標」が完了するまでパスをたどります

問題はelse、条件の最後のオプションを明確に定義する言葉です。単語のセマンティクスは、Pythonと人間の言語の両方で共有されます。しかし、人間の言語のその他の単語は、何かが完了した後に誰かまたは何かが行うアクションを示すために使用されることはありません。それを完了する過程で問題が発生した場合に使用されます(breakステートメントのように)。

最後に、キーワードはPythonに残ります。すべてのプログラマーがニーモニックデバイスのようにその使用法を理解するためにストーリーを考え出そうとしたとき、それが間違いであったことは明らかです。彼らが代わりにキーワードを選んだら、私はとても気に入りましたthen。このキーワードは、反復フロー、つまりループ後のペイオフに完全に適合していると思います。

それはおもちゃを組み立てる際のすべてのステップに従った後、いくつかの子供が持っているような状況に似ている:そして、THEN何お父さん?


この答えは、OPが話していた混乱の問題に対処していると思います。elseキーワードは、forのアクションに関連付けられているとき、elseの英語の意味から期待するものとは正反対です。理論的には、for ... elseはループが抜けたときにelse部分になってしまうという点で異なって機能する可能性がありますが、問題はそれを使用して要素xを見つけ、xが存在する場合を処理することです。見つからない場合は、全体に対して.. else構造体の後にフラグまたは別のテストを使用する必要がある場合があります
Spacen Jasset

7

「the iterableが完全に使い果たされ、実行がの終了後に次のステートメントに移ろうとするforと、else句が実行されます。」のようにそれを読みました。したがって、反復がによって中断されたbreak場合、これは実行されません。


6

私は同意します、それは「elif not [condition(s)raise break]」のようなものです。

私はこれが古いスレッドであることを知っていますが、私は今、同じ質問を調べています。私が理解している方法でこの質問に対する答えを誰かが捕らえたとは思いません。

私にとっては、「読み」の三つの方法があるelse中でFor... else、またはWhile... else同等であるすべてのそれらの文は、以下のとおりです。

  1. else == if the loop completes normally (without a break or error)
  2. else == if the loop does not encounter a break
  3. else == else not (condition raising break) (おそらくそのような条件があるか、ループがありません)

したがって、本質的に、ループ内の「else」は実際には「elif ...」であり、「...」は(1)ブレークなし、(2)NOT [条件を上げるブレーク]と同等です。

重要なのはelse、「ブレイク」がなければ意味がないため、次のものがfor...else含まれるということです。

for:
    do stuff
    conditional break # implied by else
else not break:
    do more stuff

したがって、for...elseループの重要な要素は次のとおりです。それらをわかりやすい英語で読むと次のようになります。

for:
    do stuff
    condition:
        break
else: # read as "else not break" or "else not condition"
    do more stuff

他のポスターが述べたように、ループが探しているものを見つけることができる場合、一般的にブレークが発生するため、else:は「ターゲットアイテムが見つからない場合の対処法」になります。

例外処理、ブレーク、およびforループをすべて一緒に使用することもできます。

for x in range(0,3):
    print("x: {}".format(x))
    if x == 2:
        try:
            raise AssertionError("ASSERTION ERROR: x is {}".format(x))
        except:
            print(AssertionError("ASSERTION ERROR: x is {}".format(x)))
            break
else:
    print("X loop complete without error")

結果

x: 0
x: 1
x: 2
ASSERTION ERROR: x is 2
----------
# loop not completed (hit break), so else didn't run

ブレイクがヒットした簡単な例。

for y in range(0,3):
    print("y: {}".format(y))
    if y == 2: # will be executed
        print("BREAK: y is {}\n----------".format(y))
        break
else: # not executed because break is hit
    print("y_loop completed without break----------\n")

結果

y: 0
y: 1
y: 2
BREAK: y is 2
----------
# loop not completed (hit break), so else didn't run

ブレークがなく、ブレークを発生させる条件がなく、エラーが発生しない単純な例。

for z in range(0,3):
     print("z: {}".format(z))
     if z == 4: # will not be executed
         print("BREAK: z is {}\n".format(y))
         break
     if z == 4: # will not be executed
         raise AssertionError("ASSERTION ERROR: x is {}".format(x))
else:
     print("z_loop complete without break or error\n----------\n")

結果

z: 0
z: 1
z: 2
z_loop complete without break or error
----------

6

elseキーワードは、ここで混乱することができ、多くの人々は、のようなものを指摘してきたようにnobreaknotbreakより適切です。

for ... else ...論理的に理解するためにtry...except...else、ではなくと比較してif...else...、ほとんどのPythonプログラマは次のコードに精通しています。

try:
    do_something()
except:
    print("Error happened.") # The try block threw an exception
else:
    print("Everything is find.") # The try block does things just find.

同様に、break特別な種類と考えてExceptionください:

for x in iterable:
    do_something(x)
except break:
    pass # Implied by Python's loop semantics
else:
    print('no break encountered')  # No break statement was encountered

違いはpython暗黙のexcept breakうちに書き込めないため、次のようになります。

for x in iterable:
    do_something(x)
else:
    print('no break encountered')  # No break statement was encountered

はい、私はこの比較が困難で面倒なことを知っていますが、それは混乱を明確にします。


リソースからコピーするときは、リソースへのリンクを作成する必要があります。NickCoghlanのPython Notesです。
godaygo 2017年

@godaygoリンクをありがとう。私は最初にpythonを学習するときにこの概念を読んで受け入れましたが、回答を書くときにソースを覚えていませんでした。
cizixs 2017年

@cizixsあなたは「ソースを覚えていませんでした」が、たまたまのコメントと同じコメントの文全体を含んでいたのですか?おおおおおおお。
マークアメリー2018

5

elseステートメントブロック内のコードは、forループが中断されなかったときに実行されます。

for x in xrange(1,5):
    if x == 5:
        print 'find 5'
        break
else:
    print 'can not find 5!'
#can not find 5!

ドキュメントから:ステートメントを中断して続行し、ループのelse句

ループステートメントには、else句を含めることができます。ループがリストの枯渇によって(forで)終了したとき、または条件がfalseになったときに(whileで)実行されますが、breakステートメントによってループが終了したときは実行されません。これは、素数を検索する次のループによって例示されます。

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, 'equals', x, '*', n//x)
...             break
...     else:
...         # loop fell through without finding a factor
...         print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

(はい、これは正しいコードです。よく見てください。else句は、ifステートメントではなくforループに属しています。)

ループで使用した場合、else句は、ifステートメントのそれよりも、tryステートメントのelse句との共通点が多くなります。tryステートメントのelse句は例外が発生しないときに実行され、ループのelse句はブレークが発生しないときに実行されます。 。tryステートメントと例外の詳細については、例外の処理を参照してください。

Cから借用したcontinueステートメントは、ループの次の反復を続行します。

>>> for num in range(2, 10):
...     if num % 2 == 0:
...         print("Found an even number", num)
...         continue
...     print("Found a number", num)
Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9

1
これは何も加えず、ではない質問、答えていないが、その理由を
エア

5

これについて私が上で言及した他の誰も見たことがないと思う方法があります:

まず、forループは基本的に、whileループの周りの単なる構文上の糖衣であることを思い出してください。たとえば、ループ

for item in sequence:
    do_something(item)

次のように(およそ)書き換えることができます

item = None
while sequence.hasnext():
    item = sequence.next()
    do_something(item)

次に、whileループは基本的にifブロックが繰り返されるだけであることを忘れないでください!whileループは、「この条件がtrueの場合、本体を実行してから、戻ってもう一度確認する」としていつでも読み取ることができます。

したがって、while / elseは完全に意味があります。これはif / elseとまったく同じ構造であり、条件を一度チェックするだけでなく、条件がfalseになるまでループする機能が追加されています。

そしてfor / elseも完全に理にかなっています:すべてのforループはwhileループの上にある単なる構文上の糖なので、基礎となるwhileループの暗黙の条件が何であるかを理解する必要があるだけです。条件はFalseになります。


4

素晴らしい答えは:

  • これは歴史を説明し、そして
  • これはあなたの翻訳/理解を容易にする正しい引用を与えます。

私のここでのメモは、while-elseがif-elseと区別できない、つまり(Pythonの場合)構文があるというドナルドクヌースがかつて言った(申し訳ありませんが参照できない)ことから来ています。

x = 2
while x > 3:
    print("foo")
    break
else:
    print("boo")

以下と同じフロー(低レベルの差を除く)があります。

x = 2
if x > 3:
    print("foo")
else:
    print("boo")

重要なのは、if-else breakは、ifブロックの最後に暗黙的であるwhile-elseの構文糖と見なすことができるということです。反対の含意は、そのwhileループの拡張版であるifため、より一般的な(それは単に繰り返しています/条件付きチェックをループ)であるifことが多いの前に教えていますwhile。ただし、それはelsewhile-elseのブロックが毎回実行されることを意味するため、真実ではありません条件がfalseの場合。

あなたの理解を容易にするためにそれをそのように考えてください:

、などがなければbreakreturn条件が真でなくなったときにのみループが終了し、その場合、elseブロックも1回実行されます。Pythonの場合、forCスタイルのforループ(条件付き)を考慮するか、それらをに変換する必要がありwhileます。

別のメモ:

ループ内の時期尚早breakreturnなどは、条件がtrueのときに実行がループから飛び出し、再びチェックすることはないため、条件がfalseになるのを不可能にします。


3

else他のことや他のことと同様に、ループでは行われなかったように考えることができます 。


3
for i in range(3):
    print(i)

    if i == 2:
        print("Too big - I'm giving up!")
        break;
else:
    print("Completed successfully")

「else」はクレイジーにシンプルです。

1、「for clause完了した場合」

for i in range(3):
    print(i)

    if i == 2:
        print("Too big - I'm giving up!")
        break;
if "for clause is completed":
    print("Completed successfully")

「for句が完了しました」などの長いステートメントを書くのは、「else」を導入するためです。

else ここにその性質があります。

2、しかし、どうですか for clause is not run at all

In [331]: for i in range(0):
     ...:     print(i)
     ...: 
     ...:     if i == 9:
     ...:         print("Too big - I'm giving up!")
     ...:         break
     ...: else:
     ...:     print("Completed successfully")
     ...:     
Completed successfully

したがって、完全にステートメントはロジックの組み合わせです。

if "for clause is completed" or "not run at all":
     do else stuff

または次のように記述します。

if "for clause is not partially run":
    do else stuff

またはこのように:

if "for clause not encounter a break":
    do else stuff

それ以外の場合、SQLでは「トランザクション」として機能します。
微積分

2

検索以外の慣用的な使用例を次に示します。条件が真になるのを待ちたいとしましょう。たとえば、リモートサーバーでポートが開かれ、タイムアウトが発生します。次に、次のwhile...elseような構成を利用できます。

import socket
import time

sock = socket.socket()
timeout = time.time() + 15
while time.time() < timeout:
    if sock.connect_ex(('127.0.0.1', 80)) is 0:
        print('Port is open now!')
        break
    print('Still waiting...')
else:
    raise TimeoutError()

1

私はそれを自分でもう一度理解しようとしただけです。次のことが役立つことがわかりました!

•は(の代わりに)ループelseif内側とペアになっていると考えてください。for条件が満たされた場合はループを解除し、そうでない場合はこれを実行します。ただし、1つelseが複数ifのとペアになっている場合を除きます。
ifsがまったく満たされていない場合は、を実行しelseます。
•複数のifSは、実際と考えることができますif- elifS!


-2

私は他のB(あれば)のためのような構造を考慮し、(あれば)のため-elseがある場合は、他の特別なおよそを理解するのに役立つかもしれません

AとBは、最大で1回実行されます。これは、if-else構造と同じです。

for(if)は、if条件を満たすループを実行する特別なifと見なすことができます。いったんもし条件が満たされ、Aとブレークその他、B。


-2

Pythonは、else after forループとwhileループを使用して、ループに何も適用されない場合に何かが発生するようにします。例えば:

test = 3
while test == 4:
     print("Hello")
else:
     print("Hi")

出力は何度も「こんにちは」になります(私が正しい場合)。

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