11. while ループで動作を繰り返す
プログラムでは、同じ動作を何度も繰り返す必要があることがよくあります。第 8 章では if 文で判断を行う方法を見てきましたが、特定の条件が満たされるまで動作を繰り返し実行したい場合はどうすればよいでしょうか?そこで登場するのが ループ(loop) です。
Python には 2 つの主要な種類のループがあります。while ループと for ループです。この章では while ループに焦点を当てます。while ループは、条件が真である限りコードブロックを繰り返します。シーケンスを反復処理するのに適した for ループについては、第 12 章で扱います。
while ループを理解することは、データを繰り返し処理したり、ユーザー入力を検証したり、ゲームループを実装したり、ほかにも多くの現実的なプログラミング場面に対応できるプログラムを書くための基礎になります。
11.1) while ループの構造
while ループ(while loop) は、指定した条件が True と評価されている間、コードブロックを繰り返し実行します。条件が False になるとループは停止し、プログラムはループの後ろのコードへ進みます。
基本的な while ループの構文
while ループの構造は次のようになります。
while condition:
# 繰り返すコードブロック
# このコードは condition が True の間実行されますcondition はブール値に評価される任意の式です(または第 7 章で学んだように truthy / falsy として解釈できる式です)。while 文の下でインデントされたコードブロックは ループ本体(loop body) と呼ばれ、条件が True の間、繰り返し実行されます。
簡単な例を見てみましょう。
# 1 から 5 まで数える
count = 1
while count <= 5:
print(f"Count is: {count}")
count = count + 1 # count を増やす
print("Loop finished!")Output:
Count is: 1
Count is: 2
Count is: 3
Count is: 4
Count is: 5
Loop finished!この仕組みをステップごとに見ると:
countを1に初期化します- 条件
count <= 5をチェックします。1 <= 5はTrueなので、ループ本体が実行されます - ループ内で現在の count を表示し、その後 1 を加算します
- ループ本体が終わると、Python は
while文に戻り、条件をもう一度チェックします - このプロセスは
countが6になるまで繰り返され、その時点で6 <= 5はFalseになり、ループが終了します - プログラムはループの後ろのコードへ進みます
重要なポイントは、条件が 各反復(iteration)(ループ本体の各繰り返し)の 前に チェックされることです。最初から条件が False であれば、ループ本体は一度も実行されません。
count = 10
while count <= 5:
print("This will never print")
print("Loop skipped entirely")Output:
Loop skipped entirely最初から 10 <= 5 が False なので、ループ本体は一度も実行されません。
ループ変数を変更する重要性
while ループが最終的に停止するためには、ループ内の何かが条件を True から False に変える必要があります。これは通常、条件で使っている変数(複数の場合もあります)を変更することを意味します。これを忘れると 無限ループ(infinite loop) を作ってしまいます(次のセクションで詳しく説明します)。
ループ変数を更新することがなぜ重要かを示す例です。
# 1 から 10 までの数の合計を計算する
total = 0
number = 1
while number <= 10:
total = total + number # 現在の number を total に加える
number = number + 1 # 次の number へ進む
print(f"The sum of numbers from 1 to 10 is: {total}")Output:
The sum of numbers from 1 to 10 is: 55この例では、数値を進めながら合計を蓄積しています。各反復で total と number の両方が変化しますが、ループが最終的に終了する(number が 11 になる)ことを保証しているのは number の変更です。
ユーザー入力を使う while ループ
while ループの実用的な使い方の 1 つは、特定の条件が満たされるまでユーザー入力を処理することです。簡単な数当てゲームを作ってみましょう。
# シンプルな数当てゲーム
secret_number = 7
guess = 0
while guess != secret_number:
guess = int(input("Guess the number (1-10): "))
if guess < secret_number:
print("Too low! Try again.")
elif guess > secret_number:
print("Too high! Try again.")
else:
print("Correct! You guessed it!")このループは、ユーザーが正しい数を入力するまで推測を求め続けます。各反復で 1 回分の推測を処理してフィードバックを返します。guess が secret_number と等しくなると、条件 guess != secret_number が False になり、ループは自然に終了します。
複数条件の while ループ
第 9 章で学んだように、ブール演算子(and、or、not)を使って、より複雑なループ条件を作れます。
# ユーザーが "quit" を入力するか、5 回の試行に達するまで入力を処理する
attempts = 0
user_input = ""
while user_input != "quit" and attempts < 5:
user_input = input("Enter a command (or 'quit' to exit): ")
attempts += 1
if user_input == "quit":
print("Goodbye!")
else:
print(f"You entered: {user_input}")
print(f"Attempts remaining: {5 - attempts}")
if attempts >= 5 and user_input != "quit":
print("Maximum attempts reached.")このループは 両方 の条件が真である限り続きます。つまり、ユーザーが "quit" を入力していない かつ 試行回数が 5 回を超えていない間です。どちらかの条件が偽になると、ループは終了します。
while ループの実行を可視化する
while ループがどのように実行されるかを示すフローチャートです。
ループは、条件をチェックし、条件が真なら本体を実行し、変数を更新して、再度条件をチェックするというサイクルを作ります。このサイクルは条件が偽になるまで続きます。
11.2) 無限ループとその回避方法
無限ループ(infinite loop) とは、条件が決して False にならないために終了しないループのことです。無限ループは、初心者が while ループで最もよく起こすミスの 1 つであり、プログラムがいつまでも停止しない原因になります。
無限ループの原因は?
無限ループの最も一般的な原因は、ループ条件に影響する変数を変更し忘れることです。問題のある例を見てみましょう。
# 警告: 無限ループ - デモ用のみ
# 問題: count が一度も変更されない
count = 1
while count <= 5:
print(f"Count is: {count}")
# Missing: count += 1このコードを実行すると、count が 1 のままで 1 <= 5 が常に True なので、「Count is: 1」を永遠に出力し続けます。条件が変化しません。
これが無限ループだと見抜く方法: ループ条件(count <= 5)を見て、次にループ本体の中で count を変更している箇所があるかを確認します。もし無く、かつ条件が最初から True であれば、無限ループです。
修正版はこちらです。
# 適切に増加させた正しいバージョン
count = 1
while count <= 5:
print(f"Count is: {count}")
count += 1 # これによりループは最終的に終了しますOutput:
Count is: 1
Count is: 2
Count is: 3
Count is: 4
Count is: 5安全上限を使って無限ループをデバッグする
ループを含むコードを開発するときは、テスト中にうっかり無限ループになってしまうのを防ぐために、安全上限を入れておくと便利です。
# 開発中の安全上限
count = 1
iterations = 0
max_iterations = 100 # 安全上限
while count <= 5 and iterations < max_iterations:
print(f"Count is: {count}")
count += 1
iterations += 1
if iterations >= max_iterations:
print("WARNING: Maximum iterations reached. Check for infinite loop.")このパターンでは、ループが実行された回数を追跡するカウンターを追加しています。安全上限に到達したら、ループロジックに問題があると分かります。ループが正しく動作していると確信できたら、安全上限は削除できます。
ユーザー入力を伴う無限ループ
無限ループが起きやすいもう 1 つのシナリオは、ユーザー入力の検証です。
# 警告: 無限ループになる可能性 - デモ用のみ
# 問題: ユーザーが有効な入力をしなければ、ループが終わらない
age = -1
while age < 0:
age = int(input("Enter your age: "))
# ユーザーが負の数を入力するとループが続くこのループは、ユーザーが最終的に 0 以上の値を入力すれば正しく動作しますが、ユーザーが負の値を入力し続けると無限ループになります。これはプログラムによっては許容できる場合もあります(有効な入力を受け取るまで質問し続けたい場合)が、ループの終了が完全にユーザーの振る舞いに依存していることを理解しておくことが重要です。
より堅牢なアプローチとして、終了手段を含める方法があります。
# 終了オプションを含むより良いアプローチ
age = -1
while age < 0:
user_input = input("Enter your age (or 'quit' to exit): ")
if user_input.lower() == 'quit':
print("Exiting program.")
age = 0 # ループを抜けるために有効な値に設定する
else:
age = int(user_input)
if age < 0:
print("Age must be non-negative. Please try again.")
if age > 0:
print(f"Your age is: {age}")論理エラーによる無限ループ
変数更新の方法に論理エラーがあることで、無限ループが発生する場合もあります。
# 警告: 無限ループ - デモ用のみ
# 問題: count を増加させるべきところで減少させている
count = 1
while count <= 5:
print(f"Count is: {count}")
count -= 1 # ミス: count が大きくなるのではなく小さくなるこれは無限ループになります。count は 1 から始まり 0、-1、-2 …と小さくなります。負の数は常に 5 以下なので、条件 count <= 5 は永遠に True のままです。
修正版:
count = 1
while count <= 5:
print(f"Count is: {count}")
count += 1 # 正しい: 最終的に 5 を超えるように増加させる無限ループをデバッグする
Python スクリプトの実行中に誤って無限ループを作ってしまった場合は、ターミナルで Ctrl+C(Mac の場合は Cmd+C)を押せば停止できます。これはキーボード割り込みシグナルを Python に送り、プログラムを停止させます。
無限ループを避ける方法:
- ループ条件が False になり得ることを常に確認する: 条件内の変数がループ内で変更されているかをチェックします
- 正しい比較演算子を使う:
<=、<、!=などが意図に合っているかを確認します - まず小さな値でテストする: 多数回実行され得るループは、最初に小さな上限で試します
- デバッグ用の print 文を追加する: ループ変数がどう変化するかを確認するために、一時的に出力します:
- 開発中は安全上限を使う: 先ほど示したように、テスト中は最大反復回数カウンターを追加します
11.3) while ループで break と continue を使う
Python には、ループの実行をより細かく制御するための 2 つの特別な文があります。break と continue です。これらの文を使うと、実行中に発生する条件に応じて、ループの通常の流れを変更できます。
11.3.1) break 文
break 文は、ループ条件に関係なくループを即座に終了します。Python が break に到達するとループを完全に抜け、ループの後ろのコードへ進みます。
簡単な例を見てみましょう。
# 特定の値に到達したらループを終了する
count = 1
while count <= 10:
if count == 5:
print("Reached 5, stopping loop")
break
print(f"Count: {count}")
count += 1
print("Loop exited")Output:
Count: 1
Count: 2
Count: 3
Count: 4
Reached 5, stopping loop
Loop exitedcount が 5 と等しくなると break 文が実行され、ループが即座に終了することに注目してください。条件 count <= 10 はまだ True のはずですが、ループは count = 6 まで到達しません。
break がループの流れをどう変えるか
break が通常のループ実行をどう変えるかを理解することは重要です。違いを示すフローチャートはこちらです。
重要なポイント: break は、ループから即座に抜ける経路を提供し、ループ本体の残りのコードと条件チェックの両方をバイパスします。
break の実用例: 入力検証
break の最も一般的な使い方の 1 つは、有効な入力を受け取ったらループを抜けることです。
# 有効な入力を受け取るまで質問し続ける
while True:
age_input = input("Enter your age (must be positive): ")
# 整数に変換してみる
try:
age = int(age_input)
# 有効かどうかをチェック
if age > 0:
print(f"Thank you! Your age is {age}")
break # 有効な入力でループを抜ける
else:
print("Age must be positive. Please try again.")
except ValueError:
print("That's not a valid number. Please try again.")
print("Input validation complete")このパターンでは while True: を使って意図的な無限ループを作り、break を使って有効な入力を受け取ったときに抜けます。複雑なループ条件を管理しようとするよりも、こちらのほうがすっきりします。(注: ここでは try と except を使っていますが、これについては第 VII 部で詳しく学びます。ここでは、入力を整数に変換する際のエラーを捕捉するものだと理解してください。)
複数条件での break
複雑な条件とともに break を使うと、複数の基準のいずれかが満たされたときにループを終了できます。
# ユーザー入力の中から特定の項目を探す
search_term = "python"
attempts = 0
max_attempts = 5
while attempts < max_attempts:
user_input = input("Enter a word (or 'quit' to exit): ").lower()
attempts += 1
if user_input == 'quit':
print("User requested exit")
break
if user_input == search_term:
print(f"Found '{search_term}'!")
break
print(f"'{user_input}' is not '{search_term}'. Try again.")
print(f"Attempts remaining: {max_attempts - attempts}")
if attempts >= max_attempts:
print("Maximum attempts reached")このループには 3 つの終了パターンがあります:
- ユーザーが "quit" を入力する(最初の
break) - ユーザーが検索語を入力する(2 つ目の
break) - 最大試行回数に到達する(ループ条件が
Falseになる)
11.3.2) continue 文
continue 文は、現在の反復の残りをスキップして、ループ条件のチェックに戻ります。break がループを完全に終了するのに対し、continue は次の反復へ進むだけです。
基本例はこちらです。
# 1 から 10 までの奇数だけを表示する
count = 0
while count < 10:
count += 1
if count % 2 == 0: # 偶数の場合
continue # 残りをスキップして次の反復へ
print(f"Odd number: {count}")Output:
Odd number: 1
Odd number: 3
Odd number: 5
Odd number: 7
Odd number: 9この仕組み:
- 各反復の最初に
countが増加します countが偶数(count % 2 == 0)ならcontinueが実行されますcontinue文はprint文をスキップし、while条件へ戻りますcountが奇数ならcontinueは実行されないので、print文が実行されます
continue がループの流れをどう変えるか
continue がループ実行に与える影響を示すフローチャートです。
break と continue の重要な違い:
- break: ループを完全に抜け、ループの後のコードへジャンプします
- continue: 現在の反復で残りのコードをスキップし、条件チェックへ戻ります
continue の重要な配置に関する注意
count += 1 が continue の 前 にある点に注目してください。これを後ろに置くと、偶数のときに continue が増加処理をスキップしてしまい、無限ループになります。
# 警告: 無限ループ - デモ用のみ
# 問題: continue が偶数のときに増加処理をスキップする
count = 0
while count < 10:
if count % 2 == 0:
continue # count += 1 を含め、下の処理がすべてスキップされる
count += 1 # ミス: 偶数のときにこれが実行されない
print(f"Odd number: {count}")count が 0(偶数)のとき、continue が実行されて count += 1 がスキップされます。そして再び 0 < 10 がチェックされ、同じサイクルが永遠に繰り返されます。
ルール: 条件に影響するループ変数は、ループ本体の残りをスキップし得る continue 文より 前 に必ず更新するようにしてください。
continue の実用例: データのフィルタリング
データを処理していて特定の項目をスキップしたいとき、continue 文が役立ちます。
# 有効なスコアだけを処理する
score_count = 0
total_score = 0
attempts = 0
while attempts < 5:
score_input = input(f"Enter score {attempts + 1} (or 'skip' to skip): ")
attempts += 1
if score_input.lower() == 'skip':
print("Skipping this score")
continue # 次の反復へ
try:
score = int(score_input)
if score < 0 or score > 100:
print("Score must be between 0 and 100. Skipping.")
continue # 無効なスコアをスキップする
# 有効なスコア - 処理する
total_score += score
score_count += 1
print(f"Score recorded: {score}")
except ValueError:
print("Invalid input. Skipping.")
continue
if score_count > 0:
average = total_score / score_count
print(f"\nAverage of {score_count} valid scores: {average:.1f}")
else:
print("\nNo valid scores entered")この例では continue を複数回使っています:
- ユーザーが "skip" を入力したときにスキップ
- スコアが有効範囲外のときにスキップ
- 入力が数値として無効なときにスキップ
各 continue はスコアが合計に加算されるのを防ぎますが、ループ自体は次の試行へ進みます。
break と continue の組み合わせ
同じループ内で break と continue を両方使うと、より高度な制御ができます。
# 合計が 100 を超えるまで数値を処理し、負の数はスキップする
total = 0
count = 0
while True:
number_input = input("Enter a number (or 'done' to finish): ")
if number_input.lower() == 'done':
print("User finished entering numbers")
break # ループを抜ける
try:
number = int(number_input)
if number < 0:
print("Negative numbers not allowed. Skipping.")
continue # 次の反復へ
total += number
count += 1
print(f"Added {number}. Current total: {total}")
if total > 100:
print("Total exceeded 100. Stopping.")
break # 上限に達したらループを抜ける
except ValueError:
print("Invalid input. Skipping.")
continue
print(f"\nFinal total: {total} (from {count} numbers)")このループが示していること:
- ユーザーが "done" と入力したら
breakで終了 - 負の数は
continueでスキップ - 無効な入力は
continueでスキップ - 合計が 100 を超えたら
breakで終了
11.4) while ループで else を使う
Python には、ほかの多くのプログラミング言語にはない独自の機能があります。それは while ループに else 句を付けられることです。この else ブロックは、ループが通常どおり完了した場合にのみ 実行されます(つまり break 文に遭遇せず、ループ条件が False になって終了した場合です)。
while での基本的な else 構文
構文は次のとおりです。
while condition:
# ループ本体
else:
# ループが通常どおり完了した場合にのみ実行される
# (break で中断されていない場合)簡単な例を見てみましょう。
# else 句付きで 1 から 5 まで数える
count = 1
while count <= 5:
print(f"Count: {count}")
count += 1
else:
print("Loop completed normally")
print("Program continues")Output:
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Loop completed normally
Program continuesループが条件(count <= 5)が False になるまで実行されたため、else ブロックが実行されます。ループは中断されずに「通常どおり」完了しました。
else が実行されない場合: break 文
else 句の重要な挙動は、ループが break 文で終了した場合には 実行されない ことです。
# break を使って数を検索する
count = 1
target = 3
while count <= 5:
print(f"Checking: {count}")
if count == target:
print(f"Found {target}!")
break
count += 1
else:
print("Target not found in range")
print("Search complete")Output:
Checking: 1
Checking: 2
Checking: 3
Found 3!
Search completeループが break によって終了したため、else ブロック("Target not found in range")が 実行されていない ことに注目してください。これが重要な違いです。else は、break で終了したときではなく、ループが通常どおり終了(条件が False になる)したときにのみ実行されます。
では、target が見つからない場合を見てみましょう。
# 存在しない数を検索する
count = 1
target = 7 # 1-5 の範囲にない
while count <= 5:
print(f"Checking: {count}")
if count == target:
print(f"Found {target}!")
break
count += 1
else:
print("Target not found in range")
print("Search complete")Output:
Checking: 1
Checking: 2
Checking: 3
Checking: 4
Checking: 5
Target not found in range
Search complete今回は target を見つけられないまま全反復が終わり、最終的に条件 count <= 5 が False になったため、else ブロックが実行されました。
else がループ完了とともにどう働くか
else 句があるときの実行経路を示すフローチャートです。
else ブロックに到達するのは、ループ条件が自然に False になった場合だけです。break に遭遇すると、流れは else ブロックを飛ばしてループ後のコードへ直接ジャンプします。
実用例: 検索処理
else 句は、何かが見つかったかどうかを知りたい検索処理で特に便利です。
# 試行リストの中で有効なパスワードを探す
valid_password = "python123"
max_attempts = 3
attempts = 0
while attempts < max_attempts:
password = input(f"Enter password (attempt {attempts + 1}/{max_attempts}): ")
attempts += 1
if password == valid_password:
print("Access granted!")
break
else:
print("Access denied. Maximum attempts exceeded.")
print("Account locked.")ユーザーが正しいパスワードを入力すると break が実行され、else ブロックはスキップされます。すべての試行を使い切っても成功しなければ、ループは通常どおり完了し、else ブロックが実行されて失敗を示します。
continue と else
continue 文は else ブロックの実行を妨げません。妨げるのは break だけです。
# continue は else の実行に影響しない
count = 0
while count < 5:
count += 1
if count == 3:
print(f"Skipping {count}")
continue # 次の反復へ
print(f"Processing {count}")
else:
print("Loop completed normally (continue doesn't prevent this)")Output:
Processing 1
Processing 2
Skipping 3
Processing 4
Processing 5
Loop completed normally (continue doesn't prevent this)ループが通常どおり完了したので else ブロックが実行されます。continue 文は各反復にのみ影響し、ループ全体の完了には影響しません。
break の有無で else を比較する
並べて比較してみましょう。
# 例 1: 素数を見つける(break あり)
print("Finding first number divisible by 7:")
number = 1
while number <= 20:
if number % 7 == 0:
print(f"Found: {number}")
break
number += 1
else:
print("No number divisible by 7 found in range")
print()
# 例 2: すべての数をチェックする(break なし)
print("Checking all numbers for divisibility by 7:")
number = 1
while number <= 20:
if number % 7 == 0:
print(f"Found: {number}")
number += 1
else:
print("Finished checking all numbers")Output:
Finding first number divisible by 7:
Found: 7
Checking all numbers for divisibility by 7:
Found: 7
Found: 14
Finished checking all numbers最初の例では、最初の一致が見つかった時点で break によりループが停止するので、else は実行されません。2 つ目の例では、ループはすべての数をチェックして通常どおり完了するため、else が実行されます。
while ループで else を使うべき場面
else 句が最も役立つのは次のようなときです。
- 検索処理: 何かが見つかったかどうかを知りたい
- 回数制限のある検証: 試行回数を使い切った場合の処理が必要
- 早期終了を含む処理: 「全部完了した」と「途中で止めた」で異なる振る舞いをさせたい
ただし、ループの else は、ほかの言語から来たプログラマ(この機能が存在しない言語の出身者)にとって混乱しやすいことがあります。フラグ変数を使ったほうが明確な場合もあります。
# else 句を使う
attempts = 0
while attempts < 3:
password = input("Enter password: ")
attempts += 1
if password == "secret":
print("Access granted")
break
else:
print("Access denied")
# フラグ変数を使った同等の方法(こちらのほうが分かりやすいこともある)
attempts = 0
access_granted = False
while attempts < 3:
password = input("Enter password: ")
attempts += 1
if password == "secret":
print("Access granted")
access_granted = True
break
if not access_granted:
print("Access denied")どちらの方法も動作します。あなたの状況でコードがより明確になるほうを選んでください。
while ループの else を理解すると、特に検索や検証のシナリオで「見つかった/見つからなかった」や「成功/全試行後の失敗」を区別する必要がある場合に、より明確で表現力のあるコードを書くためのツールが増えます。
この章では while ループを深く掘り下げ、次のことを学びました。
- 条件に基づいてコードを繰り返すループの構造
- ループ変数を適切に更新して無限ループを避ける方法
- 必要に応じて
breakでループを早期終了する方法 - 条件に応じて
continueで反復をスキップする方法 breakなしでループが通常どおり完了した場合をelseで扱う方法
これらの道具により、プログラム内の繰り返しを強力に制御できます。次の章では、文字列、リスト(list)、range などのシーケンスを反復処理するための、より便利な方法である for ループについて学びます。