for文などのループを途中で抜けるためにはbreakやcontinueを使いますが、外側からも一気に抜けたいことがあります。
for〜elseを使う
Python3のdocによると、
最初のスイートの中で break 文が実行されると、 else 節のスイートを実行することなくループを終了します。 continue 文が最初のスイート内で実行されると、スイート内にある残りの文の実行をスキップして、次の要素の処理に移るか、これ以上次の要素が無い場合は else 節の処理に移ります。
だそうです。つまり、for文内部でbreakが実行されるとelse文がスキップされます。なんだか直感的じゃないような気もしますが、これを活用すれば以下のように書けそうです。
for i in range(10):
for j in range(10):
print(f"{i} : {j}")
if i == 5 and j == 5:
break
else:
continue
break
print("end")
これで”5 : 5″までコンソールに出力された時点で外側のループからも抜けます。何もしなければelse節に移るので、そこでcontinueして直下のbreak文を毎回飛ばすことで、ループさせています。
直感的であろうはずがありませんし、知ってる人が見たとしてもhackyであり、決して可読性に優れているとは思えません。
メソッドに切り出す
なので、メソッドに切り出すのが良い方法です。こちらのほうが余程シンプルに書けます。
def loop():
for i in range(10):
for j in range(10):
print(f"{i} : {j}")
if i == 5 and j == 5:
return
loop()
print("end")
returnでいつでも抜けられますから、可読性にも優れていますね。以下に3重ネストの例を書いておきましょう。内側のループのみをreturnで抜けますが、外側はそのまま続きます。
def innerloop(outer_i):
for i in range(10):
for j in range(10):
print(f"{outer_i} : {i} : {j}")
if i == 5 and j == 5:
return
for i in range(3):
innerloop(i)
print("end")
”0 : 5 : 5″、 ”1 : 5 : 5″、 “2 : 5 : 5″で内側のループが終わっていることがわかります。
また、外側のループを内側の条件分岐で抜けたい場合もあります。この場合は、以下のようにreturn文に意味を持たせれば上手く書けるはずです。
def innerloop(outer_i):
for i in range(10):
for j in range(10):
print(f"{outer_i} : {i} : {j}")
if i == 5 and j == 5:
return outer_i == 1 # 外側のループのiが1ならTrueを返す
for i in range(3):
should_break = innerloop(i)
if should_break:
break # innerloopの返り値がTrueならbreakする
print("end")
まとめ
for〜elseは構文としてはあるものの、外側のループを制御するために使うのは可読性を損ないますし、あまり筋が良い方法ではありません。適切にメソッドを切り分けることで、簡潔な書き方をすることができます。どんどんメソッドを活用していきましょう。