Pythonのループと条件分岐:for、while、range、enumerate、break、if/elif、match/case
Pythonのループは処理を繰り返す仕組みです。forはリストや範囲(range())の要素を順に取り出し、whileは条件が成り立つ間繰り返します。breakでループを抜け、continueで今の回の残りを飛ばし、enumerate()で番号を付けられます。判断にはif/elif/elseを使い、データの形で分岐するならmatch/case(Python 3.10以降)を使います。
Pythonのループは、同じ処理を繰り返すために使います。買い物リストを1行ずつ処理する、ファイルの各行を読み込む、正しい数字が入力されるまで質問を続ける、といった場面です。Pythonのループには for と while の2種類があります。その中で判断するには if/elif/else の条件分岐や match/case を使います。ここでは、それぞれの道具を実際に使える例とともに見ていきます。
条件分岐:if、elif、else
if文は、条件式が真のときだけブロックを実行します。ブロックは4つのスペースのインデントで示します。Pythonには波かっこがないため、インデントが正しくないと、すぐに IndentationError が出ます。
spent = 4200
limit = 5000
if spent > limit:
print("予算を超えました")
elif spent > limit * 0.8:
print("予算の残りは20%未満です")
else:
print("問題ありません")
elif の条件は上から順に調べられ、最初に当てはまったものだけが実行されます。そのため、厳しい条件は上に書きます。もし spent > limit * 0.8 を先頭に置くと、予算超過のメッセージは決して表示されません。
何が「真」とみなされるか
条件に比較式を書く必要はありません。偽とみなされるのは False、None、ゼロ(0、0.0)、空のコレクション(""、[]、{})です。それ以外はすべて真です。そのため「リストが空でないか」は短く書けます。
expenses = []
if not expenses:
print("まだ支出はありません")
条件は and、or、not で組み合わせられます。範囲の判定は比較を連ねて書けます。例:if 0 < amount <= 100_000:。短い選択には三項演算子も使えます。例:status = "多め" if spent > limit else "通常"。
Pythonのforループ:構文と例
Pythonの for は、Cのようなカウンタではなく、要素を1つずつ取り出す仕組みです。リスト、文字列、辞書、ファイル、範囲など、繰り返し可能なオブジェクトの要素を先頭から順に受け取ります。他の言語でいうforeachにあたるのが、Pythonの通常の for です。
expenses = [350, 1200, 89, 4500]
total = 0
for amount in expenses:
total += amount
print(total) # 6139
構文は for 変数 in コレクション: で、その後にインデントされたブロックが続きます。ループが終わった後も、変数には最後の値が残ります。これが役立つこともありますが、大きなプログラムで頼るのはおすすめしません。
文字列、リスト、辞書のループ
文字列は1文字ずつ、リストは要素ごとに処理されます。辞書をそのままループすると、キーが順に取り出されます。キーと値を同時に取り出すには .items() を使います。
by_category = {"食費": 3200, "交通費": 900, "映画": 600}
for category, amount in by_category.items():
print(f"{category}: {amount}円")
値だけを取り出すには .values() を使います。ループの途中で辞書のサイズを変えるとエラーになります。RuntimeError: dictionary changed size during iteration が出ます。要素を削除したい場合は、コピーを回しましょう。例:for key in list(d):。
range関数:数字で繰り返す
数字を順に回したいときは range() を使います。range() はメモリ上にリストを作らず、数字を1つずつ生成するので、range(10**9) でも一瞬で準備できます。
| 呼び出し | 生成される数字 |
|---|---|
range(5) | 0, 1, 2, 3, 4 |
range(2, 6) | 2, 3, 4, 5 |
range(0, 10, 3) | 0, 3, 6, 9 |
range(5, 0, -1) | 5, 4, 3, 2, 1 |
覚えておくべきルールは、終わりの値は範囲に含まれないことです。range(1, 10) は9で終わります。これは「1つずれる」エラーのよくある原因です。ステップは負にできますが、0にはできません。
for i in range(1, 4):
print(f"{i}日目")
# 1日目
# 2日目
# 3日目
enumerate:ループの中で番号を付ける
要素の番号が必要なとき、初心者は for i in range(len(items)) と書きがちです。動きますが、読みにくくなります。enumerate() は「番号と要素」のペアを返します。start 引数で、数え始める番号を指定できます。
items = ["コーヒー", "タクシー", "昼食"]
for n, item in enumerate(items, start=1):
print(n, item)
# 1 コーヒー
# 2 タクシー
# 3 昼食
2つのリストを並行して回すには zip() を使います。例:for name, price in zip(names, prices):。zip() は最も短いリストで止まります。Python 3.10以降では strict=True を渡すと、長さが違うときにエラーになります。
Pythonのwhileループ
while は、条件が真の間ブロックを繰り返します。繰り返し回数が事前に分からないときに使います。正しい入力を待つ、データを最後まで読む、成功するまで問い合わせを繰り返す、といった場合です。
balance = 10_000
month = 0
while balance > 0:
balance -= 2_700
month += 1
print(f"お金は{month}か月分あります") # 4
大きな落とし穴は、条件に使っている変数を変えるのを忘れることです。そうするとループが終わりません。プログラムが止まってしまったら、Ctrl+C を押してください。Pythonは KeyboardInterrupt で実行を中断します。
無限ループとdo while
無限ループは、わざと書くこともあります。while True: を書き、break で抜けるパターンです。Pythonには do while 構文がありません。代わりに、このパターンが後判定のループの役割を果たします。ブロックは必ず1回は実行され、判定はブロックの最後に来ます。
while True:
raw = input("金額: ")
if raw.isdigit():
amount = int(raw)
break
print("整数を入力してください")
for で無限ループを作るのは珍しく、itertools.count() のような無限のイテレータを回すときだけです。
breakとcontinue:ループを抜ける、回を飛ばす
break はループを直ちに終わらせ、ループの後のコードに進みます。continue は、今の回の残りを飛ばして次の回に進みます。
expenses = [350, -10, 1200, 0, 99_999, 89]
for amount in expenses:
if amount <= 0:
continue # この回をスキップ
if amount > 50_000:
print("不審な金額のため停止します")
break # ループを抜ける
print(amount)
表示されるのは 350 と 1200 で、その後に警告が出てループが終わります。89 には到達しません。どちらの文も、自分を含む一番内側のループに対してだけ働きます。
ループのelse
for と while には、少し珍しい else 節もあります。ループが break なしで最後まで回ったときに実行されます。検索処理に便利です。
for amount in expenses:
if amount > 50_000:
print("大きな支出を見つけました")
break
else:
print("大きな支出はありません")
多重ループ(ネストしたループ)
ループの中にループを入れると、内側のループは外側の1回ごとに最後まで実行されます。表や行列を回ったり、組み合わせを作ったりするときに使います。
for row in range(1, 4):
for col in range(1, 4):
print(row * col, end="\t")
print()
注意点が2つあります。1つ目は、計算量が急に増えることです。10,000個の要素を持つ2重ループは、1億回の処理になります。2つ目は、break が抜けられるのは内側のループだけという点です。両方を止めたいなら、ループを関数に入れて return で抜けるのが、フラグを使うより分かりやすい方法です。
match/caseの使い方
Python 3.10以降では、if cmd == ... elif ... が長く続くときに match 文(PEP 634)が使えます。これは単なるswitchではありません。値を形のパターンと照合し、同時にその一部を変数に取り出せます。
def parse(text):
match text.split():
case ["add", item, amount]:
return f"追加 {item}: {amount}"
case ["list"] | ["ls"]:
return "支出を表示"
case ["quit"]:
return "終了"
case _:
return "不明なコマンドです"
print(parse("add コーヒー 250")) # 追加 コーヒー: 250
print(parse("add コーヒー")) # 不明なコマンドです
パターン ["add", item, amount] に一致するのは、要素がちょうど3つで、先頭が "add" のリストだけです。金額のないコマンドは、すべてを受け止める _ の節に入ります。| は複数の候補をまとめます。
辞書のパターンとガード条件
辞書のパターンは、書いたキーだけを確認し、ほかのキーは無視します。int(a) は型を確認すると同時に値を取り出します。パターンの後に if を付けると、追加の条件(ガード)になります。
match event:
case {"type": "expense", "amount": int(a)} if a > 10_000:
print("大きな支出", a)
case {"type": "expense", "amount": int(a)}:
print("支出", a)
matchの一番の落とし穴
case の後に裸の名前を書くと、それは比較ではなく取り込み(キャプチャ)になります。case limit: はどんな値にも一致し、その値を limit に入れてしまいます。定数と比べたいときは、case Color.RED: のようにドット付きの名前を使うか、リテラルを書きます。
Python 3.10以降でmatchの構文はほとんど変わっていません。Python 3.15では、小さな非対称性が解消されました。以前は、リテラルのパターンで数字の前にマイナス記号を付けた形しか使えませんでした。今は case +1: も書けます。古いバージョンでは、このコードは構文エラーになります。
ループでよくあるミス
- ループ中にリストを変更する。
forの中で要素を削除すると、隣の要素が飛ばされます。新しいリストを作るのが安全です。例:clean = [x for x in items if x > 0]。 - rangeの終わり。
range(1, n)はnを含みません。 - whileで条件の変数を変えない。 無限ループになります。
- ループの中で
+=で文字列を連結する。 量が多いと、"".join(parts)より遅くなります。 - 比較の代わりに代入する。
if x = 5は構文エラーです。比較には==を使います。
ループの練習問題
- 支出のリストから、負の値を除いて合計と平均を計算する。
- 多重ループで、1〜9の九九の表を表示する。
- ユーザーが空文字を入力するまで数字を尋ね、最後に最大値を表示する。
- リストの中で最初に1000より大きい数字を探し、なければその旨を表示する(
for ... elseを使う)。 matchでadd、del、listのコマンドを解釈する。
まとめ
Pythonのループは、基本的に2つの文です。for はコレクションや range() の要素を順に処理し、while は条件が真の間繰り返します。break と continue で流れを制御し、enumerate() と zip() は手作業のカウンタを不要にし、if/elif/else と match/case が判断を担当します。これらの道具はすべて、講座の家計簿ツールを題材にした講義で実際に使いながら解説しています。
よくある質問
Pythonのforとwhileの違いは何ですか?
forは用意された並びを順に処理し、いつ終わるかを自分で把握しています。whileは条件が真の間繰り返します。回数が決まっているか、コレクションを回すならfor、何かの出来事を待つならwhileを選びましょう。
ループを逆順に回すにはどうすればよいですか?
コレクションなら reversed(items)、数字なら range(n - 1, -1, -1) を使います。reversed はリストをコピーせず、後ろから読み進めます。
Pythonにswitch文はありますか?
独立したswitch文はありません。その役割は if/elif の連なりと、Python 3.10で導入された match/case が担います。matchはリストや辞書を形で分解し、値を取り出すこともできるため、より多くのことができます。
ループと内包表記のどちらが速いですか?
[x * 2 for x in items] のような内包表記は、同じ処理をappendで書いたループより少し速く、短く書けます。複数の条件を含む複雑な処理は、通常のループの方が読みやすいでしょう。
二重ループを一度に抜けるにはどうすればよいですか?
breakは内側のループだけを抜けます。ループを関数に入れ、returnで抜けるのが簡単です。