2.1.5 フロー制御

このページを終えたら、この evidence card を残します。
- 概念
- 変数、型、演算子、入力/出力、分岐、ループ、構造、関数、またはモジュール
- コード
- この概念のための最小限の実行可能な Python スニペット
- 出力
- 印字値、型、branch結果、loop trace、または返り値
- 失敗確認
- 型不一致、インデント、オフバイワン、可変データ、または import パスの問題
- 期待される成果
- 概念が機能することを証明するコードと出力結果
この節の位置づけ
Section titled “この節の位置づけ”この節では、プログラムに「判断させる」ことと「繰り返し実行させる」ことを学びます。条件分岐とループは、あらゆる自動化スクリプト、データ処理フロー、モデル学習コードの土台です。これらを身につけると、コードはもう上から下へ順番に実行されるだけではなくなります。
if/elif/elseによる条件分岐を身につけるforループとwhileループを身につけるbreak、continueを使ってループを制御できるようになる- 入れ子のロジックを含むプログラムを書けるようになる
フロー制御とは?
Section titled “フロー制御とは?”ここまでに書いてきたコードは、すべて上から下へ1行ずつ実行されるものでした。でも実際のプログラムでは、判断したり、繰り返したりする必要があります。これがフロー制御です。
朝、家を出るときの判断を思い浮かべてみましょう。
もし 雨が降っていたら: 傘を持つそれ以外で もし 日差しが強ければ: 帽子をかぶるそれ以外: そのまま出かけるこれが条件分岐です。
次に、単語を覚えるときのことを考えてみましょう。
100回繰り返す: 新しい単語を見る 覚えるこれがループです。
条件分岐: if / elif / else
Section titled “条件分岐: if / elif / else”基本の if
Section titled “基本の if”failed_tests = 3
if failed_tests > 0: print("リリースを止めて、失敗したテストを確認します。")文法ルール:
ifの後に条件式を書く- 条件の後にはコロン
:を付ける(初心者がよく忘れます) - 条件が成り立つときに実行するコードは4スペースでインデントする
if…else
Section titled “if…else”all_checks_passed = False
if all_checks_passed: print("ビルドはデプロイできます") print("リリースノートを書きます")else: print("ビルドはレビュー状態のままにします") print("失敗したチェックを先に直します")if…elif…else
Section titled “if…elif…else”elif は “else if” の略で、複数の条件を順番に確認するときに使います。
latency_ms = 185
if latency_ms < 100: status = "高速"elif latency_ms < 200: status = "正常"elif latency_ms < 500: status = "遅め"else: status = "重大"
print(f"API レイテンシ: {latency_ms} ms、状態: {status}")# 出力: API レイテンシ: 185 ms、状態: 正常条件分岐の省略形
Section titled “条件分岐の省略形”# 三項演算子(1行で簡単な if-else を書く)latency_ms = 185status = "予算内" if latency_ms <= 200 else "要確認"print(status) # 予算内
# 同じ意味if latency_ms <= 200: status = "予算内"else: status = "要確認"入れ子の if
Section titled “入れ子の if”条件の中にさらに条件を書けます。
has_approval = Trueall_tests_passed = False
if has_approval: if all_tests_passed: print("このビルドをデプロイします") else: print("テストスイートの通過を待ちます")else: print("先にリリース承認を依頼します")ただし、入れ子が深すぎると読みづらくなるので、通常は3階層を超えないようにするのがおすすめです。
for ループ
Section titled “for ループ”for ループは、シーケンス(リスト、文字列、範囲など)に含まれる各要素を順番にたどるために使います。
リストをたどる
Section titled “リストをたどる”services = ["ログイン API", "検索 API", "Worker", "ダッシュボード"]
for service in services: print(f"{service} をチェックします")
# 出力:# ログイン API をチェックします# 検索 API をチェックします# Worker をチェックします# ダッシュボード をチェックします理解のしかたとしては、for service in services は「services の中の1つ1つの service について、下のコードを実行する」という意味です。
文字列をたどる
Section titled “文字列をたどる”word = "Python"
for char in word: print(char, end=" ")
# 出力: P y t h o nrange() 関数
Section titled “range() 関数”range() は数字の並びを作る関数で、for ループの相棒としてよく使われます。
# range(5) は 0, 1, 2, 3, 4 を作るfor i in range(5): print(i, end=" ")# 出力: 0 1 2 3 4
# range(start, stop) は start から stop-1 までfor i in range(1, 6): print(i, end=" ")# 出力: 1 2 3 4 5
# range(start, stop, step) は step 付きfor i in range(0, 10, 2): print(i, end=" ")# 出力: 0 2 4 6 8
# 逆順for i in range(5, 0, -1): print(i, end=" ")# 出力: 5 4 3 2 1実践例: レビュー時間を合計する
Section titled “実践例: レビュー時間を合計する”total_minutes = 0for day in range(1, 6): total_minutes += 30print(f"5日分のレビュー時間: {total_minutes} 分") # 150enumerate():インデックスと値を同時に取得する
Section titled “enumerate():インデックスと値を同時に取得する”tasks = ["ログインフォーム設計", "API エンドポイント実装", "スモークテスト作成"]
# 普通の書き方for i in range(len(tasks)): print(f"タスク {i+1}: {tasks[i]}")
# より Pythonic な書き方:enumerate を使うfor i, task in enumerate(tasks): print(f"タスク {i+1}: {task}")
# 開始番号を指定するfor i, task in enumerate(tasks, start=1): print(f"タスク {i}: {task}")while ループ
Section titled “while ループ”while ループは、条件が成り立っている間ずっと実行され、条件が成り立たなくなると止まります。
基本の使い方
Section titled “基本の使い方”count = 0
while count < 5: print(f"現在のカウント: {count}") count += 1 # 条件を更新するのを忘れないでください!
print("ループ終了")
# 出力:# 現在のカウント: 0# 現在のカウント: 1# 現在のカウント: 2# 現在のカウント: 3# 現在のカウント: 4# ループ終了while がよく使われる場面
Section titled “while がよく使われる場面”while は、ループ回数が決まっていない場合に向いています。
# 場面: バックグラウンドジョブの完了を待つjob_status = "queued"poll_count = 0
while job_status != "finished": poll_count += 1 print(f"{poll_count} 回目のポーリング: {job_status}")
if poll_count == 1: job_status = "running" elif poll_count == 2: job_status = "finished"
print(f"ジョブは {poll_count} 回のポーリング後に完了しました")for と while はどう選ぶ?
Section titled “for と while はどう選ぶ?”| 場面 | おすすめ | 理由 |
|---|---|---|
| リスト/文字列をたどる | for | 自然に向いている |
| 回数が決まっているループ | for + range() | 簡潔でわかりやすい |
| 回数が決まっていないループ | while | 柔軟に制御できる |
| ある条件が成り立つのを待つ | while | 直感的 |
経験則: for が使えるなら for を使いましょう。より安全です(無限ループになりにくいです)。
break と continue
Section titled “break と continue”break: ループをすぐ終了する
Section titled “break: ループをすぐ終了する”# 最初の遅いリクエストを見つけたら止めるlatencies_ms = [120, 145, 310, 180, 260]
for latency_ms in latencies_ms: if latency_ms > 250: print(f"最初の遅いリクエスト: {latency_ms} ms") break print(f"{latency_ms} ms は範囲内です。続けて確認します...")
# 出力:# 120 ms は範囲内です。続けて確認します...# 145 ms は範囲内です。続けて確認します...# 最初の遅いリクエスト: 310 mscontinue: 今回のループだけ飛ばして、次へ進む
Section titled “continue: 今回のループだけ飛ばして、次へ進む”# 遅いリクエストだけを表示し、正常なものは飛ばすlatencies_ms = [95, 210, 180, 260, 130]
for latency_ms in latencies_ms: if latency_ms <= 200: continue # 正常なリクエストをスキップ print(latency_ms, end=" ")
# 出力: 210 260break と continue の違い
Section titled “break と continue の違い”# break: ループを完全に抜けるfor i in range(10): if i == 5: break # 5 になったらループ全体を終了 print(i, end=" ")# 出力: 0 1 2 3 4
# continue: 今回だけ飛ばして、次へ進むfor i in range(10): if i == 5: continue # 5 を飛ばして、6, 7, 8, 9 へ進む print(i, end=" ")# 出力: 0 1 2 3 4 6 7 8 9ループの else
Section titled “ループの else”Python のループには、少し特別な else があります。ループが正常に終了したとき、つまり break で止められなかったときに実行されます。
# 必須レビューが不足していないか調べるcompleted_checks = ["unit-test", "lint", "api-test"]required_check = "security-review"
for check in completed_checks: if check == required_check: print(f"{required_check} は完了しています") breakelse: # ループが break で終わらなかったので、必須チェックは見つからなかった print(f"{required_check} が不足しています")
# 出力: security-review が不足しています入れ子ループ
Section titled “入れ子ループ”ループの中に、さらにループを書けます。
# モジュール/チェックの表を表示するmodules = ["API", "UI", "DB"]checks = ["lint", "test"]
for module in modules: for check in checks: print(f"{module}:{check}", end="\t") print() # 各モジュールの終わりで改行出力:
API:lint API:testUI:lint UI:testDB:lint DB:test例1: AI モデル学習の流れをシミュレートする
Section titled “例1: AI モデル学習の流れをシミュレートする”import random
print("=== モデル学習開始 ===")print(f"{'Epoch':<10}{'Loss':<15}{'Accuracy':<15}{'Status'}")print("-" * 50)
loss = 2.5accuracy = 0.10
for epoch in range(1, 21): # 学習を模擬する: 損失は徐々に下がり、精度は徐々に上がる loss *= random.uniform(0.85, 0.95) accuracy = min(accuracy + random.uniform(0.03, 0.06), 1.0)
# 学習状態を判断する if accuracy >= 0.95: status = "✅ 達成" elif accuracy >= 0.80: status = "📈 良好" else: status = "🔄 学習中"
print(f"{epoch:<10}{loss:<15.4f}{accuracy:<15.2%}{status}")
# 精度が 98% に達したら早期終了 if accuracy >= 0.98: print(f"\n早期終了!第 {epoch} エポックで目標精度に到達しました") breakelse: print(f"\n学習完了!最終精度: {accuracy:.2%}")例2: パスワード強度チェッカー
Section titled “例2: パスワード強度チェッカー”password = input("パスワードを入力してください: ")
has_upper = False # 大文字があるかhas_lower = False # 小文字があるかhas_digit = False # 数字があるかhas_special = False # 特殊文字があるか
for char in password: if char.isupper(): has_upper = True elif char.islower(): has_lower = True elif char.isdigit(): has_digit = True else: has_special = True
# 強度スコアを計算するscore = 0if len(password) >= 8: score += 1if has_upper: score += 1if has_lower: score += 1if has_digit: score += 1if has_special: score += 1
# 結果を出力するprint(f"\nパスワード強度: {'★' * score}{'☆' * (5 - score)} ({score}/5)")
if score <= 2: print("弱いパスワードです!強化をおすすめします")elif score <= 4: print("中くらいの強さです")else: print("強いパスワードです!")やってみよう
Section titled “やってみよう”練習1: リリースチェックラベル
Section titled “練習1: リリースチェックラベル”分岐の順番を、小さなリリースチェックのラベル付けで練習します。
1 から 50 までのサンプル番号を表示してください。ただし、
- 15 で割り切れるなら “FullCheck” を表示する
- 3 で割り切れるなら “Lint” を表示する
- 5 で割り切れるなら “Test” を表示する
- それ以外は数字そのものを表示する
for i in range(1, 51): if i % 15 == 0: print("FullCheck") elif i % 3 == 0: print("Lint") elif i % 5 == 0: print("Test") else: print(i)ヒント: まず 15 で割り切れるかを判定し、その後で 3 と 5 を判定します。
練習2: レイテンシ告警ループ(サンプル数制限あり)
Section titled “練習2: レイテンシ告警ループ(サンプル数制限あり)”最大 7 個のレイテンシサンプルを確認し、しきい値を超えたらすぐ停止しましょう。
latencies_ms = [120, 180, 260, 140, 310, 190, 170]threshold_ms = 250max_samples = 7
for sample_no, latency_ms in enumerate(latencies_ms[:max_samples], start=1): print(f"サンプル {sample_no}: {latency_ms} ms")
if latency_ms <= threshold_ms: print("正常") continue
print("告警: レイテンシがしきい値を超えました") breakelse: print("確認したサンプルはすべてしきい値内でした。")練習3: デプロイ進捗バーを表示する
Section titled “練習3: デプロイ進捗バーを表示する”ループを使って次の進捗表示を出してください。
###############次に、カウントダウンの進捗バーも表示してみましょう。
###############練習4: 失敗したチェックを見つける
Section titled “練習4: 失敗したチェックを見つける”ステータスが "passed" ではないチェック名をすべて表示してください。
checks = [ ("lint", "passed"), ("unit-test", "failed"), ("api-test", "passed"), ("security-review", "failed"),]
for check_name, status in checks: if status == "passed": continue print(f"{check_name}: {status}")参考実装と解説
- リリースチェックラベルでは、先に
15で割り切れるかを判定します。そうしないと15が先にLintやTestとして出力される可能性があります。 - レイテンシリストでは、固定データを使って、正常パス、告警パス、遅い値を取り除いたすべて正常のパスを確認します。
- 進捗バーは
for n in range(1, 6): print("#" * n)で表示できます。カウントダウンには逆向きのrangeを使います。 - 失敗チェックの抽出では
"passed"に対してcontinueを使い、失敗または未通過のステータスだけを表示します。 - 境界ミスに注意します。
range(1, 51)は50を含み、range(1, 50)は含みません。
| 文法 | 用途 | 重要ポイント |
|---|---|---|
if/elif/else | 条件分岐 | 条件は上から順にチェック。コロンとインデントを忘れない |
for...in | シーケンスをたどる | range()、リスト、文字列と一緒に使う |
while | 条件ループ | 条件の更新を忘れず、無限ループを避ける |
break | ループを終了する | ループ全体をすぐ抜ける |
continue | 今回を飛ばす | 現在の反復を飛ばして次へ進む |
range() | 数字の並びを作る | range(start, stop, step) |