Pythonループの `else`句をどのように理解できますか?


191

多くのPythonプログラマーはおそらく、whileループとforループの構文にオプションのelse:句が含まれていることを認識していません。

for val in iterable:
    do_something(val)
else:
    clean_up()

else句の本体は、特定の種類のクリーンアップアクションに適した場所であり、ループの通常の終了時に実行されます。returnつまりbreakelse句を使用してループを終了するか、句をスキップします。continue実行後に終了します。私はちょうどこの理由だけ知っている、それを見上げ、私は覚えていることはできませんので、(再び)ときelse句が実行されます。

常に?名前が示すように、ループの「失敗」について?定期的に終了しますか?ループが終了してもreturn?私はそれを調べなければ、完全に確信を持つことはできません。

私はキーワードの選択がelse根強く残っていることを非難します。このセマンティクスには信じられないほどニーモニックだと思います。私の質問は「なぜこのキーワードがこの目的で使用されているのか」(回答とコメントを読んだ後でのみ、投票する可能性がある)ではなくelseキーワードの意味を理解するためにキーワードをどのように考えることができますか。したがって、それを覚えることができますか?

私はこれについてかなりの量の議論があったと思います、そして私はtryステートメントのelse:条項(私も調べなければならない)との一貫性のために、そしてリストに追加しないことを目標にして作られた選択を想像することができますPythonの予約語。おそらく、選択した理由によってelseその機能が明確になり、覚えやすくなりますが、私は名前を機能に関連付けた後です。歴史的な説明自体ではありません。

回答この質問私の質問は簡単に興味深いバックストーリーがたくさん含まれている、の重複として閉鎖されました、。私の質問は別の焦点(特定のセマンティクスとelseキーワードの選択を関連付ける方法)を持っていますが、この質問へのリンクがどこかにあるはずです。


23
「反復するものが残っている場合は...」
OneCricketeer

4
この質問を書いた後は、今すぐ覚えていると思います:)
Jasper

11
これelseは基本的に「継続条件が失敗した場合」を意味します。従来のforループでは、継続条件は通常i < 42です。この場合、その部分はif i < 42; execute the loop body; else; do that other thing
njzk2

1
これはすべて真実であり、私は特にdrawocの答えが好きですが、考慮すべきもう1つのことは、構文的に多少意味のある利用可能なキーワードがあることです。あなたはtry / exceptを知っているかもしれませんし、おそらくtry / except / finallyを知っているかもしれませんが、それはにも持っています - 例外が起こらなかったらこのコードを実行しください。これは、このコードをtry節に示すのと同じことではありません。狭い範囲をターゲットとする場合は、例外処理が最適です。したがって、概念的な意味はありますが、ここでの多数の回答によると、これもゲームでのキーワードの再利用だと思いますが、これを特定の条件下で実行します
JL Peyret

1
@Falanwe、コードがによって終了されるときに違いがありますbreak。正規のユースケースは、ループが何かを検索し、それが見つかったときにブレークする場合です。else何も見つからなかった場合にのみ実行されます。
アレクシス2016年

回答:


212

(これは@Mark Tolonenの答えに触発されています。)

if文はその実行されelse、その条件がfalseと評価された場合の句を。同様に、while条件がfalseと評価された場合、ループはelse句を実行します。

このルールは、説明した動作と一致します。

  • 通常の実行では、条件がfalseと評価されるまでwhileループが繰り返し実行されるため、自然にループを終了するとelse句が実行されます。
  • breakステートメントを実行すると、条件を評価せずにループを終了するため、条件がfalseと評価されず、else句が実行されることはありません。
  • continueステートメントを実行すると、条件が再度評価され、ループ反復の開始時に通常行うのとまったく同じことが行われます。したがって、条件がtrueの場合はループし続けますが、falseの場合はelse句を実行します。
  • など、ループを終了する他のメソッドはreturn条件を評価しないため、else句は実行されません。

forループは同じように動作します。イテレータにさらに要素がある場合は条件をtrueと見なし、そうでない場合はfalseと見なします。


8
これは最も優れた答えです。ループを一連のelifステートメントのように扱うと、elseの動作によってその自然なロジックが公開されます。
ノメネーター

1
私もこの答えが好きですが、それは一連のelifステートメントとの類似点を描いていません。あります答えはありません、それは1つのネットupvoteがあります。
アレクシス2016年

2
厳密には正確ではありませんが、whileループはbreaksの直前に条件をFalseに満たす可能性があります。その場合、elseは実行されませんが、条件はFalseです。同様に、forループの場合break、最後の要素で行うことができます。
Tadhg McDonald-Jensen 2016

36

このように考えると良いelseでしょう。前のブロックですべてが正しく実行され、枯渇に達した場合、ブロックは常に実行されます。for

この文脈における権利exception、いいえbreak、いいえ、いいえを意味しreturnます。制御をハイジャックするステートメントはforelseブロックをバイパスさせます。


でアイテムを検索するときに一般的な使用例が見つかりiterableます。アイテムが見つかったとき、または"not found"次のelseブロックを介してフラグが立てられたり印刷されたりすると、検索が中止されます。

for items in basket:
    if isinstance(item, Egg):
        break
else:
    print("No eggs in basket")  

Aは、continueからハイジャックしない制御を行うfor制御がに進みますので、else後にfor排出されます。


20
とてもいい音に聞こえます...しかし、あなたはelse物事がうまくいかないときに節が実行されることを期待するでしょうね?私はもう混乱しています...
アレクシス

私はであなたと同意しなければならない「技術的には、それは、[他のすべてのと意味的に類似していないelseことから、]」else私は証明として、forループ内の条件のいずれも、Trueに評価されなかったときに実行される私の答え
Tadhg McDonald-ジェンセン

@ TadhgMcDonald-Jensenでループを解除することもできますFalse。それでは、どのように質問forされて壊れては、ユースケースに依存します。
Moses Koledoye 2016年

そうです、「else」の英語の意味に何が起こるかをどうにかして関連付ける方法を求めています(これは実際elseにpythonの他の使用法に反映されています)。else@Moses が何をするかについての直感的な要約を提供しますが、この動作を「else」と関連付ける方法については提供しません。別のキーワードが使用された場合(たとえば、関連する質問へのこの回答でnobreak述べられているように)、それは理解しやすくなります。
アレクシス

1
それは本当に「うまくいく」こととは何の関係もありません。elseは、if/ while条件がfalseと評価された場合、またはfor項目の外にある場合にのみ実行されます。 breakを含むループが存在します(の後にelse)。 continue戻ってループ条件を再度評価します。
Mark Tolonen 2016年

31

いつif実行しelseますか?条件が偽の場合。これはwhile/でもまったく同じですelse。したがって、while/はelseiffalseと評価されるまでそのtrue条件を実行し続けるものと考えることができます。A breakはそれを変更しません。それは、評価なしで包含ループからジャンプするだけです。else場合にのみ実行される評価if / while条件が偽です。

forその偽の条件はそのイテレータを排出されることを除き、同様です。

continuebreak実行しないでくださいelse。それは彼らの機能ではありません。break含むループを終了します。continueループ条件が評価され含むループの先頭に戻ります。これは、評価の行為ですif/ whilefalseに(またはforこれ以上の項目がある)ことを実行elseしていない他の方法を。


1
非常に賢明に聞こえますが、3つの終了条件をまとめて、「[条件]がFalseになるか、中断/継続するまで」は間違っています:重要なことにelse、ループがcontinue(または正常に)終了すると、句が実行されますが、終了した場合ではありませんbreak。これらの微妙さが、私が何をelseキャッチし、何をキャッチしないのかを本当に理解しようとしている理由です。
アレクシス2016年

4
@alexisはい、明確にする必要がありました。編集。continueはelseを実行しませんが、ループの先頭に戻り、ループの先頭でfalseと評価される場合があります。
Mark Tolonen 2016年

24

これは本質的にそれが意味することです:

for/while ...:
    if ...:
        break
if there was a break:
    pass
else:
    ...

これは、この一般的なパターンを記述するより良い方法です。

found = False
for/while ...:
    if ...:
        found = True
        break
if not found:
    ...

else句があれば実行されませんreturnので、returnそれが意味するように、葉の機能。あなたが考えている可能性のある唯一の例外はですfinally。その目的は、常に実行されることを確認することです。

continueこの件に関して特別なことは何もありません。これにより、ループの現在の反復が終了し、ループ全体が終了する場合があります。その場合、明らかに、ループはで終了していませんbreak

try/else 似ています:

try:
    ...
except:
    ...
if there was an exception:
    pass
else:
    ...

20

ループをこれに似た構造(やや疑似コード)と考える場合:

loop:
if condition then

   ... //execute body
   goto loop
else
   ...

それはもう少し理にかなっているかもしれません。ループは基本的にif、条件がになるまで繰り返される単なるステートメントですfalse。そしてこれが重要なポイントです。ループはその条件をチェックし、それがであることを確認しますfalse。したがって、else(通常のようにif/else)を実行し、ループが完了します。

したがってelse 、条件がチェックされたときに実行されるの唯一のgetであることに注意してください。つまり、a returnやa などを使用して実行の途中でループの本体を終了するとbreak、条件は再度チェックelseされないため、ケースは実行されません。

continue一方、A は現在の実行を停止してからジャンプしてループの状態を再度確認しelseます。このため、このシナリオではに到達できます。


私はこの答えを大いに気に入っていますが、簡単に言うことができます。endラベルを省略して、ただ本文のgoto loop中に入れifます。たぶんif、ラベルと同じ行に置くことでインデントし、突然それはオリジナルに非常によく似ています。
Bergi

@Bergiはい、私はそれがそれを少し明確にすると思います、ありがとう。
京湾

15

ループのと私の知っておかなけれ瞬間else、私がすることによって話見ていたとき句だったレイモンドヘッティンガー彼は、それが呼ばれている必要がありますと思ったかについて話をしました、nobreak。次のコードを見てください。どうすればよいと思いますか?

for i in range(10):
    if test(i):
        break
    # ... work with i
nobreak:
    print('Loop completed')

何だと思いますか?まあ、言う部分はnobreakbreakステートメントがループでヒットしなかった場合にのみ実行されます。


8

通常、私はこのようなループ構造を考える傾向があります:

for item in my_sequence:
    if logic(item):
        do_something(item)
        break

可変数のif/elifステートメントのようになるには:

if logic(my_seq[0]):
    do_something(my_seq[0])
elif logic(my_seq[1]):
    do_something(my_seq[1])
elif logic(my_seq[2]):
    do_something(my_seq[2])
....
elif logic(my_seq[-1]):
    do_something(my_seq[-1])

この場合、elseforループのelseステートメントはelifs のチェーンのステートメントとまったく同じように機能し、Trueと評価される前の条件が1つもない場合にのみ実行されます。(またはreturn例外を使用して実行を中断する)私のループがこの仕様に適合しない場合、私は通常、for: elseこの質問を投稿した正確な理由で使用をオプトアウトすることを選択します。直感的ではありません。


正しい。ただし、ループは複数回実行されるため、これをforループに適用する方法が少し不明確です。明確にできますか?
アレクシス2016年

@alexis私は私の答えをやり直しました、私はそれが今ずっとはっきりしていると思います。
Tadhg McDonald-Jensen 2016

7

他の人はすでにの仕組みを説明してwhile/for...elseおり、Python 3言語リファレンスには信頼できる定義があります(whileforを参照)が、ここに私の個人的なニーモニック、FWIWがあります。私の鍵は、これを2つの部分に分解することだったと思います。1つelseはループ条件との関連での意味を理解するため、もう1つはループ制御を理解するためです。

私は理解することから始めるのが最も簡単だと思いますwhile...else

whileあなたはより多くのアイテムを持っています、else何かをします、あなたが足りなくなったら、これをしてください

for...elseニーモニックは、基本的には同じです。

forすべてのアイテム、else何かを行いますが、不足した場合はこれを行います

どちらの場合も、else処理するアイテムがなくなり、最後のアイテムが通常の方法で処理された(つまり、breakまたはreturn)場合にのみ、パーツに到達します。A continueが戻って、さらに項目があるかどうかを確認します。これらの規則のための私のニーモニックは、両方に適用されますwhilefor

ときbreakINGのか、returnINGの、何もありませんelse行うには、
と私が言うときcontinue、あなたのための「ループバックが起動する」ということ

–「ループバックトゥスタート」の意味で、明らかに、ループに関しては、反復可能オブジェクトにさらに項目があるかどうかをチェックします。ループelseに関しては、に関する限り、continueまったく何の役割も果たしません。


4
for / elseループの通常の目的は、探しているものが見つかり、停止したいか、またはアイテムがなくなるまでアイテムを調べることであると言って、それを強化することをお勧めします。「else」は、「アイテムが足りない(探しているものが見つからなかった)」部分を処理するために存在します。
スーパーキャット2016

@supercat:可能性はありますが、最も一般的な用途はどこにあるのかわかりません。elseまた、あなたは、単にすべての項目を終了している何かをするために使用することができます。例としては、ログエントリの書き込み、ユーザーインターフェイスの更新、完了したその他のプロセスの通知などがあります。なんでも、本当に。また、一部のコードはbreakループの内側で「成功」ケースが終了しelse、反復中に適切なアイテムが見つからなかった「エラー」ケースを処理するために使用されます(おそらくそれがあなたが考えていたものでした)の?)。
Fabian Fagerholm 2016

1
私が考えていたときでした正確に成功の欠如「休憩」と成功したケースが終了した場合、および「他」のハンドル。ループ内に「ブレーク」がない場合、「else」コードは、囲んでいるブロックの一部としてループに従うだけです。
スーパーキャット2016

ループが中断することなくすべての反復可能な項目を通過した場合(およびそれが成功した場合)とそうでない場合を区別する必要がない限り。次に、ループのelseブロックに「ファイナライズ」コードを配置するか、他の手段を使用して結果を追跡する必要があります。基本的に同意します。この機能の使用方法がわからないので、「else成功したケースをelse処理する」シナリオと「失敗したケースを処理する」シナリオのどちらが一般的であるかを想定しないようにします。しかし、あなたは良い点を持っているので、コメントを投票してください!
Fabian Fagerholm 2016

7

テスト駆動開発使用している場合(TDD)、転換優先前提のパラダイムを、あなたは条件文の一般化として、ループを扱います。

単純なif/else(なしelif)ステートメントのみを検討する場合、このアプローチはこの構文とうまく組み合わせられます。

if cond:
    # 1
else:
    # 2

一般化して:

while cond:  # <-- generalization
    # 1
else:
    # 2

うまく。

他の言語では、TDDが単一のケースからコレクションのあるケースに進むには、より多くのリファクタリングが必要です。


これは8thlightブログのです

8thlightブログのリンクされた記事では、Word Wrap kataが考慮されています:文字列(s以下のスニペットの変数)に改行を追加して、それらを特定の幅(length以下のスニペットの変数)に合わせます。ある時点では、実装は次のようになります(Java)。

String result = "";
if (s.length() > length) {
    result = s.substring(0, length) + "\n" + s.substring(length);
} else {
    result = s;
}
return result;

そして次のテストは、現在失敗しています:

@Test
public void WordLongerThanTwiceLengthShouldBreakTwice() throws Exception {
    assertThat(wrap("verylongword", 4), is("very\nlong\nword"));
    }

したがって、条件付きで機能するコードがあります。特定の条件が満たされると、改行が追加されます。複数の改行を処理するようにコードを改善したいと考えています。記事で提示されているソリューションは、(if-> while)変換を適用することを提案していますが、作者は次のようにコメントしています。

ループにはelse句を含めることができないため、elseパスで実行する処理を少なくして、パスを削除する必要がありifます。繰り返しますが、これはリファクタリングです。

これは、1つの失敗したテストのコンテキストでコードにさらに変更を加えることを強制します。

String result = "";
while (s.length() > length) {
    result += s.substring(0, length) + "\n";
    s = s.substring(length);
}
result += s;

TDDでは、テストに合格するためにできる限り少ないコードを記述したいと考えています。Pythonの構文のおかげで、次の変換が可能です。

から:

result = ""
if len(s) > length:
    result = s[0:length] + "\n"
    s = s[length:]
else:
    result += s

に:

result = ""
while len(s) > length:
    result += s[0:length] + "\n"
    s = s[length:]
else:
    result += s

6

私がそれを見る方法はelse:、あなたがループの終わりを過ぎて繰り返すとき発砲します。

あなたの場合breakまたはreturnまたはraiseあなたが反復は、ループの終わりを越えてはいけない、あなたはimmeadiately停止、ひいてはelse:ブロックは実行されません。continueループの終わりを過ぎてもまだ反復する場合、continueは次の反復にスキップするだけなので。ループは止まりません。


1
私はそれが好きだ、私はあなたが何かをしていると思う。これは、悪い昔のループキーワードの前にループが実装されていた方法と少し結びついています。(つまり、チェックはループの最下部に配置され、goto成功した場合はトップになります。)しかし、これはトップ投票の回答の短いバージョンです...
alexis

@alexis、主観的ですが、私はそれを表現する私の方法が考えやすいと思います。
Winston Ewert 2016年

実際に同意します。それがより細いという理由だけで。
アレクシス2016年

4

else節はループ構造の一部であると考えてください。breakループ構造から完全に抜け出し、else節をスキップします。

しかし、実際には、私のメンタルマッピングは、単にパターン化されたC / C ++パターンの「構造化」バージョンであるということです。

  for (...) {
    ...
    if (test) { goto done; }
    ...
  }
  ...
done:
  ...

したがって、直接for...else理解するのではなく、自分で遭遇したり記述したりするときは、精神的にそれを上記のパターンの理解に変換してから、Python構文のどの部分がパターンのどの部分にマッピングされるかを調べます。

(違いはコードが構造化されているか非構造化されているかではなく、特定の構造に専用のキーワードと文法があるかどうかだけなので、私は「構造化」を恐怖の引用符で囲みました)


1
どこにあるのelsedone:ラベルがプロキシまたはを表すことを意味している場合else:、私はあなたがそれを正確に逆に持っていると信じています。
アレクシス2016

@alexis「else」コードは、ラベルの直前に「...」を入力しdone:ます。全体的な対応は、おそらく、このように最もよく言われelseます。Python には-on-loop構造があるため、この制御フローパターンをなしで表現できますgoto
zwol 2016

フラグを設定するなど、この制御フローパターンを実行する他の方法があります。それはelse避けています。
アレクシス2016

2

とペアリングするelsefor、混乱を招く可能性があります。キーワードelseがこの構文に適しているとは思いませんが、within とペアリングelseするifbreak、実際に意味があることがわかります。else前のifステートメントがない場合はほとんど役に立ちません。これが、構文デザイナーがキーワードを選択した理由だと思います。

それを人間の言葉で説明しましょう。

for容疑者のグループの各人はif誰でもbreak捜査の犯人 です。else失敗を報告します。


1

私の考えでは、重要なのは continueはなくですelse

あなたが言及する他のキーワードはループから抜け出します(異常に終了します) continueそうではなく、ループ内のコードブロックの残りをスキップするだけです。ループの終了に先行できるという事実は偶発的です。終了は、実際にはループ条件式の評価によって通常の方法で行われます。

次に、else句は通常のループ終了後に実行されることを覚えておく必要があります。


0
# tested in Python 3.6.4
def buy_fruit(fruits):
    '''I translate the 'else' below into 'if no break' from for loop '''
    for fruit in fruits:
        if 'rotten' in fruit:
            print(f'do not want to buy {fruit}')
            break
    else:  #if no break
        print(f'ready to buy {fruits}')


if __name__ == '__main__':
    a_bag_of_apples = ['golden delicious', 'honeycrisp', 'rotten mcintosh']
    b_bag_of_apples = ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
    buy_fruit(a_bag_of_apples)
    buy_fruit(b_bag_of_apples)

'''
do not want to buy rotten mcintosh
ready to buy ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
'''
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.