2.

Python の while 文|無限ループの防ぎ方・break/continue・else 節

編集
この記事の要点
  • while 条件:条件が真である間くり返す。回数が決まっていない処理に使う
  • Python に do-while は無いwhile True: + 末尾の if ...: break で書く
  • カウンタの更新を忘れると無限ループになる。抜けたいときは Ctrl + C
  • while...elsebreak しなかったときに実行される(条件が偽になって終わったとき)
  • 要素を順に処理するだけなら while ではなく for を使う

基本形

n = 3
while n > 0:
    print(n)
    n -= 1          # ← これを忘れると無限ループ
print("終了")

# 3
# 2
# 1
# 終了

条件はループに入る前に評価されます。最初から偽なら本体は 1 度も実行されません。

do-while の代わり

Python には「まず 1 回実行してから条件を見る」構文がありません。while Truebreak の組み合わせが定番です。

while True:
    answer = input("続けますか? (y/n): ")
    if answer in ("y", "n"):
        break                       # 正しい入力が来たら抜ける
    print("y か n を入力してください")

print(f"入力は {answer} でした")

入力チェックやリトライのように「まずやってみて、結果を見て続けるか決める」処理はこの形になります。

無限ループとその止め方

# よくある無限ループ
n = 3
while n > 0:
    print(n)        # n を減らしていないので永久に 3 が出続ける

# 条件が浮動小数点だと止まらないことがある
x = 0.0
while x != 1.0:     # 0.1 を 10 回足しても 1.0 ちょうどにはならない
    x += 0.1

# 比較演算子で書けば止まる
x = 0.0
while x < 1.0:
    x += 0.1
原因対処
カウンタを更新していない本体の最後で必ず更新する
if の中でしか更新していない条件に当たらない経路でも進むようにする
float== / != で比べている< > で比べる
外部からの終了条件が来ない最大回数の上限を別に設ける

実行中に止めたいときはターミナルで Ctrl + CKeyboardInterrupt)です。Jupyter Notebook では停止ボタン(■)を押します。

break と continue

n = 0
while n < 10:
    n += 1
    if n % 2 == 0:
        continue        # 偶数はここで次の周回へ
    if n > 7:
        break           # 7 を超えたら抜ける
    print(n)            # 1 3 5 7

continueカウンタ更新の前に置くと無限ループになりますwhilecontinue を使うときは、更新をループ本体の先頭に置くのが安全です。詳細は 繰り返しの中断 (break)繰り返しのスキップ (continue) を参照してください。

while...else

retry = 0
while retry < 3:
    if try_connect():           # 成功したら抜ける
        print("接続できました")
        break
    retry += 1
else:
    print("3 回試して失敗しました")   # break されずに条件が偽になった

else は「break せずに終わったとき」に実行されます。「リトライを使い切った」「探したが見つからなかった」の分岐を、フラグ変数なしで書けます。

回数上限を必ず付ける

import time

MAX_ATTEMPTS = 5
attempt = 0

while attempt < MAX_ATTEMPTS:
    attempt += 1
    if fetch():
        break
    time.sleep(2 ** attempt)     # 指数的に待ち時間を伸ばす
else:
    raise RuntimeError(f"{MAX_ATTEMPTS} 回試しても取得できませんでした")

外部サービスの応答を待つループは、終了条件が来ない可能性を常に想定します。回数上限と待ち時間をセットにしておくと、相手が落ちていてもプログラムが固まりません。

while と for の使い分け

状況使うもの
リスト・辞書・ファイルの各行を順に処理for
決まった回数くり返すfor i in range(n)
条件が満たされるまで(回数不明)while
入力・受信を待ち続けるwhile Truebreak
items = ["a", "b", "c"]

# while で回すと添字管理が必要で間違えやすい
i = 0
while i < len(items):
    print(items[i])
    i += 1

# for なら添字が要らない
for item in items:
    print(item)

添字を自分で進める while が出てきたら for に置き換えられないかを先に考えます。番号も欲しい場合は enumerate() を使います。

番兵(センチネル)で終わりを判定する

# 空行が来たら終わり、という入力ループ
lines = []
while True:
    line = input("入力(空行で終了): ")
    if line == "":
        break
    lines.append(line)

print(f"{len(lines)} 行受け取りました")

# ファイルを 1 行ずつ読む(readline は EOF で "" を返す)
with open("data.txt", encoding="utf-8") as f:
    while (line := f.readline()):
        print(line.rstrip())

readline()ファイル末尾で空文字を返します。改行だけの行は "\n" なので空文字ではなく、正しく区別できます。ただしファイルを読むだけなら for line in f: のほうが簡単です。

電卓のような対話ループ

total = 0

while True:
    raw = input("数値(q で終了): ").strip()

    if raw.lower() == "q":
        break

    try:
        total += float(raw)
    except ValueError:
        print("数値を入力してください")
        continue          # 合計は変えずに次の入力へ

    print(f"現在の合計: {total}")

print(f"最終結果: {total}")

入力の検証は try で囲み、失敗したら continue で次に進めます。この形なら、どんな入力が来てもループから抜けずに処理を続けられます。例外の扱いは 例外処理 を参照してください。

ジェネレータの代わりに使う

# ページ送りのある API を最後まで取り切る
page = 1
items = []

while True:
    res = fetch(page)                # 1 ページぶん取得
    items.extend(res["items"])

    if not res["has_next"]:
        break
    page += 1
    if page > 100:                    # 保険の上限
        raise RuntimeError("ページ数が想定を超えました")

print(len(items))

「何回で終わるか事前に分からない」処理は while の出番です。相手のデータ次第で回数が決まる場合こそ、保険の上限を入れておきます。

while で書くと危ないパターン

書き方問題代わりに
while i < len(items): で添字を進める更新忘れ・オフバイワンfor item in items:
while x != 1.0:(float)誤差でちょうど一致しないwhile x < 1.0:
ループ内でリストから削除しながら回す要素が飛ばされる新しいリストを作る
while True:break が無い止まらない終了条件を必ず書く
ネットワーク待ちを while で空回しCPU を使い切るtime.sleep() を挟む

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 条件分岐 (if文)
  2. 繰り返し処理(while文)
  3. 繰り返し処理
  4. 繰り返しの中断 (break)
  5. 繰り返しのスキップ (continue)

最近更新/作成されたページ