Pythonでプログラミングをしていると、ループ処理を何度も繰り返す「多重ループ(ネストされたループ)」を使いたい場面がよくあります。
しかし、多重ループの中から特定の条件で一気に処理を抜けたいとき、単純なbreak
ではうまくいかないことがあります。
この記事では、Pythonで多重ループをbreak
文を使って意図通りに抜ける方法や、break
以外のスマートな脱出方法について、初心者の方にも分かりやすく解説します。
【本記事の信頼性】
- 執筆者は元エンジニア
- 大手プログラミングスクールのWebディレクター兼ライターを経験
- 自らも地元密着型のプログラミングスクールを運営
プログラミングスクール
■Webエンジニアの育成に特化 ■自社開発企業への転職成功率がダントツ ■ハイスキルを求める人に最適 |
|
■サポートは半永久的 ■単価80万円以上の講師陣 ■AWSやJavaに強い |
|
■受講料完全無料 ■最短1か月で卒業 ■教室への通学も可能 |
Pythonでの多重ループとは
多重ループとは、ループ文の中に別のループ文が含まれている構造を指します。
2重ループ、3重ループなど、ネストの深さによって呼び方が変わりますが、最も一般的なのは2重ループでしょう。
以下は基本的な2重ループの例です。
for i in range(3):
for j in range(3):
print(f"i={i}, j={j}")
このコードを実行すると、以下のような結果が出力されます。
i=0, j=0
i=0, j=1
i=0, j=2
i=1, j=0
i=1, j=1
i=1, j=2
i=2, j=0
i=2, j=1
i=2, j=2
このような構造では、特定の条件で内側のループだけでなく、外側のループも含めて完全に抜け出したい場面が多くあります。
2重ループをbreakで抜ける方法
通常のbreak文は、そのbreak文が含まれているループのみを終了させます。
2重ループで内側のループにbreakを記述した場合、内側のループのみが終了し、外側のループは継続されます。
for i in range(3):
for j in range(3):
if i == 1 and j == 1:
break
print(f"i={i}, j={j}")
print(f"外側のループ: i={i}")
【実行結果】
i=0, j=0
i=0, j=1
i=0, j=2
外側のループ: i=0
i=1, j=0
外側のループ: i=1
i=2, j=0
i=2, j=1
i=2, j=2
外側のループ: i=2
上記の例では、i=1、j=1の条件でbreakが実行されますが、内側のループのみが終了し、外側のループは継続されています。
このため、i=2の場合も処理が実行されてしまいます。
多重ループをbreakで抜ける方法
多重ループを完全に抜けるためには、いくつかの方法があります。
最も基本的で分かりやすい方法を紹介していきます。
フラグ変数を使用する
フラグ変数を使用して、外側のループにも終了条件を設定する方法です。
flag = False
for i in range(5):
for j in range(5):
print(f"i={i}, j={j}")
if i == 2 and j == 2:
flag = True
break
if flag:
break
print("ループを抜けました")
【実行結果】
i=0, j=0
i=0, j=1
i=0, j=2
i=0, j=3
i=0, j=4
i=1, j=0
i=1, j=1
i=1, j=2
i=1, j=3
i=1, j=4
i=2, j=0
i=2, j=1
i=2, j=2
ループを抜けました
フラグ変数flagをFalseで初期化し、ループを抜けたい条件でTrueに設定します。
内側のループでbreakした後、外側のループでフラグをチェックして、Trueの場合は外側のループもbreakで抜けるという仕組みです。
else節とbreakを組み合わせる
Pythonのforループにはelse節があり、これを活用する方法もあります。
for i in range(5):
for j in range(5):
print(f"i={i}, j={j}")
if i == 2 and j == 2:
break
else:
continue
break
print("ループを抜けました")
【実行結果】
i=0, j=0
i=0, j=1
i=0, j=2
i=0, j=3
i=0, j=4
i=1, j=0
i=1, j=1
i=1, j=2
i=1, j=3
i=1, j=4
i=2, j=0
i=2, j=1
i=2, j=2
ループを抜けました
forループのelse節は、ループが正常に完了した場合(breakで中断されなかった場合)にのみ実行されます。
内側のループでbreakが実行されると、else節はスキップされ、外側のbreakが実行される仕組みです。
関数とreturnを使用する
多重ループを関数内に記述し、returnで抜ける方法は非常にすっきりしています。
def process_nested_loop():
for i in range(5):
for j in range(5):
print(f"i={i}, j={j}")
if i == 2 and j == 2:
return
print("すべてのループが完了しました")
process_nested_loop()
print("関数を抜けました")
【実行結果】
i=0, j=0
i=0, j=1
i=0, j=2
i=0, j=3
i=0, j=4
i=1, j=0
i=1, j=1
i=1, j=2
i=1, j=3
i=1, j=4
i=2, j=0
i=2, j=1
i=2, j=2
関数を抜けました
returnを使用することで、関数全体を抜けることができるため、多重ループからも簡単に抜けることができるでしょう。
多重ループをbreak以外で抜ける方法
break以外にも、多重ループを抜ける方法がいくつかあります。
場面に応じて適切な方法を選択することが大切でしょう。
例外を使用する
カスタム例外を定義して、多重ループを抜ける方法です。
class BreakLoop(Exception):
pass
try:
for i in range(5):
for j in range(5):
print(f"i={i}, j={j}")
if i == 2 and j == 2:
raise BreakLoop()
except BreakLoop:
pass
print("ループを抜けました")
【実行結果】
i=0, j=0
i=0, j=1
i=0, j=2
i=0, j=3
i=0, j=4
i=1, j=0
i=1, j=1
i=1, j=2
i=1, j=3
i=1, j=4
i=2, j=0
i=2, j=1
i=2, j=2
ループを抜けました
この方法では、BreakLoopという例外クラスを定義し、ループを抜けたいタイミングで例外を発生させています。
try-except文でこの例外をキャッチすることで、多重ループから抜け出すことができます。
itertools.productを使用する
itertools.productを使用すると、多重ループを1つのループとして扱えます。
import itertools
for i, j in itertools.product(range(5), range(5)):
print(f"i={i}, j={j}")
if i == 2 and j == 2:
break
print("ループを抜けました")
【実行結果】
i=0, j=0
i=0, j=1
i=0, j=2
i=0, j=3
i=0, j=4
i=1, j=0
i=1, j=1
i=1, j=2
i=1, j=3
i=1, j=4
i=2, j=0
i=2, j=1
i=2, j=2
ループを抜けました
itertools.productは、複数のイテラブルの直積を生成するため、2重ループと同じ効果を得ることができます。
1つのループになるため、通常のbreakで抜けることが可能です。
ジェネレータ関数を使用する
ジェネレータ関数を使用して、多重ループの処理を分離する方法もあります。
def generate_coordinates():
for i in range(5):
for j in range(5):
yield i, j
for i, j in generate_coordinates():
print(f"i={i}, j={j}")
if i == 2 and j == 2:
break
print("ループを抜けました")
【実行結果】
i=0, j=0
i=0, j=1
i=0, j=2
i=0, j=3
i=0, j=4
i=1, j=0
i=1, j=1
i=1, j=2
i=1, j=3
i=1, j=4
i=2, j=0
i=2, j=1
i=2, j=2
ループを抜けました
ジェネレータ関数generate_coordinatesは、座標の組み合わせを順次生成します。
このジェネレータを使用することで、メインのループは1つになり、通常のbreakで抜けることができます。
Pythonで多重ループを抜ける際の注意点
多重ループを扱う際には、いくつかの注意点があります。
適切な方法を選択し、可読性の高いコードを書くために、以下のポイントを押さえておきましょう。
パフォーマンスを意識する
例外を使用する方法は、例外処理にオーバーヘッドが発生するため、頻繁に実行される処理では避けるべきでしょう。
以下のような場面では、フラグ変数や関数を使用する方法が適しています。
# 推奨されない例(例外を頻繁に使用)
class BreakLoop(Exception):
pass
for outer in range(1000):
try:
for inner in range(1000):
if some_condition(): # 頻繁に条件が満たされる
raise BreakLoop()
except BreakLoop:
continue
上記のような場合、例外処理のコストが積み重なり、パフォーマンスが劣化する可能性があります。
可読性を保つ
コードの可読性を保つために、複雑な制御構造は避けるべきでしょう。
以下は、可読性の悪い例です。
# 可読性の悪い例
for i in range(10):
for j in range(10):
for k in range(10):
if condition1:
if condition2:
flag = True
break
if flag:
break
if flag:
break
このような深いネストは、バグの温床になりやすく、メンテナンスが困難になります。
関数に分割したり、早期returnを使用したりして、構造を簡潔にすることが重要でしょう。
メモリ使用量に注意する
大きなデータを扱う多重ループでは、メモリ使用量に注意が必要です。
ジェネレータを活用することで、メモリ効率を改善できるでしょう。
# メモリ効率の悪い例
data = [[i * j for j in range(10000)] for i in range(10000)]
for row in data:
for value in row:
if value > threshold:
break
# メモリ効率の良い例
def generate_data():
for i in range(10000):
for j in range(10000):
yield i * j
for value in generate_data():
if value > threshold:
break
ジェネレータを使用することで、必要な分だけデータを生成し、メモリ使用量を大幅に削減できます。
まとめ
Pythonで多重ループをbreakで抜ける方法について、様々なアプローチを紹介しました。
それぞれの方法には特徴があるので、使用する場面に応じて適切な方法を選択することが重要となります。
なお、Pythonを体系的に学んだり、Pythonのスキルを高めたりするためには、プログラミングスクールを利用するのも有効です。
細かな疑問がすぐに解決するだけでなく、現役エンジニアが「質の高いポートフォリオ」を作成するための手助けをしてくれたり、エンジニア就職・転職のコツを教えてくれたりするなど、様々なメリットがありますので、独学に疲れた方は検討してみてはいかがでしょうか。
