zaki work log

作業ログやら生活ログやらなんやら

[Python] すべてのループを処理してきた者達だ。面構えが違う。(for/whileのelse節)

C/Java/Perlとかで育ってるとPythonの構文はときどきギョッとすることがあって、その一つがループのelse節だったりして調べても割とすぐ忘れてしまうので、備忘録としてインパクトあるタイトルを付けたのでこれでもう大丈夫。たぶん。

TL;DR

Pythonforwhileループにはelseがあり、breakでループを途中で抜けなかった場合に実行したい処理を書ける。

items = [1,2,3,4,5]

for item in items:
    print(item)
    if (item == 1000):
        break
else:
    print("すべてのループを処理してきた配列だ。面構えが違う。")

説明のためなので例が悪い(後述)けど、このループはitems配列内に1000があると途中でbreakするロジックになっているが、配列内に1000はないため条件は成立せずにループの最後まで処理される。結果else節が実行されるため「すべてのループを処理してきた配列だ。面構えが違う。」が出力される。
breakの条件文が3とかであればbreakするため、else節は実行されない。

whileも同様に、ループ条件が偽になってループ終了した場合にelse節が実行される。

使いどころ

リストなどで要素が無ければ作成・あれば何もしない

リストのループ処理内で存在チェックして、あればbreak、なければelse節で作成処理的なことを行えば、フラグ変数を使った条件分岐なしで実装できる。

イメージとしてはこんな感じ。

for item in item_list:
    if (item == 作成対象):
        print(item + ' is exist')
        break

else:
    print(item + ' is not found')
    create_item(item)
    item_list.append(item)

多重ループから抜ける

たぶん慣れてないと読み取りづらいので、多言語のロジックと同様にフラグを使った方が良いかもしれないが…とサンプルコード書こうと思ったけど、以下を見た方が早い。

note.nkmk.me

他にも活用方法あったら教えてください。

最初の悪い例の解説

Pythonにはリスト内の要素の有無を判定するinがあるので、前述のような単純な要素チェックであればそもそもループにしなくてよい。

if (1000 not in items):
    print('items に 1000 はない')

配列要素が辞書型で特定キーの内容を判定処理を実装した別関数で処理する、みたいにちょっとややこしい判定処理になってくると威力を発揮できるかも。