まとめ
Python の for 文は for 節の後に else 節を取ることができ、この else 節は「break することなくループを終了したとき」に実行される [1]。else の語義 (=そうではなく) に寄せるなら、「次のアイテムを取り出そうとしたら (あるのではなく) もうなかったとき」に実行される処理と捉えるとよいかもしれない。
しかし、やはり語義から混乱を招き、バグの温床にもなり、Python 開発者もこの命名はよくなかったと思っているようなので [2]、使わない方が無難かもしれない。
Python の for 文は for 節の後に else 節を取れる。while 文も同様である。
8. 複合文 (compound statement) — Python 3.14.2 ドキュメント#the-for-statement
if __name__ == '__main__':
for i in [0, 1, 2]:
print(i)
else:
print('else clause')
……いや、else とは何なのか。オブジェクトを反復処理するのに「その他」も何もないだろう。この節はいつ実行されるのか、と思うかもしれない。
初見だと何となく、この else 節は「オブジェクトが空だったときには」なのではないかと思うかもしれない。が、オブジェクトが空であろうとなかろうと else 節は実行される。
あるいは、try 文の except 節が例外を捕捉するように、「break を捕捉したときには」なのではないかとも思うかもしれないが、break せずとも else 節は実行されている。むしろ、break したときにこそ else 節は実行されない。それが else 節の仕様である (以下)。
8. 複合文 (compound statement) — Python 3.14.2 ドキュメント#the-for-statement
最初のスイートの中で break 文が実行されると、 else 節のスイートを実行することなくループを終了します。
しかし、else という言葉から「break することなくここまで到達した暁には」という意味は読み取りづらいように思われる。どうにもその逆の、「想定と異なった場合には」のようにみえてしまう。
ただここで、Python の for 文の内部動作が「オブジェクトからイテレータを取得し、順に次のアイテムを取り出す」というものであることを知っていれば、この else 節は「次のアイテムを取り出そうとしたらもうなかったときには (= StopIteration が送出されたときには)」の意味だったのかと捉えることができるかもしれない。
さらに、下記リンクの Stack Overflow 記事の回答によると、Python コア開発者の Raymond Hettinger 氏曰く、開発当時には、計算機科学者 Donald Knuth の提言を背景に、for 文の後の else 節は「正常終了の出口」と認識される期待があったのだという。しかし、氏は「今思えば "nobreak" 節とした方が混乱しなかった」とも考えているようである。
if statement - Why does python use 'else' after for and while loops? - Stack Overflow
- The for ... else construct was devised by Donald Knuth as a replacement for certain GOTO use cases;
- Reusing the else keyword made sense because "it's what Knuth used, and people knew, at that time, all [for statements] had embedded an if and GOTO underneath, and they expected the else;"
- In hindsight, it should have been called "no break" (or possibly "nobreak"), and then it wouldn't be confusing.*
実際、同 Stack Overflow 記事の以下の回答者はこの else 節の建設的な利用方法 (else 節に来たら目的のアイテムが見つからなかったことをフラグなしに検知できる糖衣構文) を提示しているのだが、この回答にはネガティブなコメントが並ぶ。
if statement - Why does python use 'else' after for and while loops? - Stack Overflow
- この糖衣構文はプロジェクトを虫歯にするだろう。
- else としたのは本当に間違いだと思う。passed や completed ならよかったのに。
- もし for-else が if 節内にあったら、保守担当者がバグだと思い込んで else 節を if 節に合わせるために何度もインデントを戻すことになるでしょうね。
なので、あなたがよほど使いたくてそのコードは本当にあなたしか読み書きしない、というのでもない限り、for-else (while-else) は使わない方が無難なのではないかとは思う。