Python 控制結構:邏輯決策與迴圈控制 (第 2 章)

站主自己的課程,請大家支持
揭秘站長的架站心法:如何利用 Hugo × AI 打造高質感個人品牌網站? 揭秘站長的架站心法:如何利用 Hugo × AI 打造高質感個人品牌網站?
  • Post by
  • Dec 16, 2023
post-thumb

在掌握了變數與資料型別後,下一步就是讓程式具備「思考」的能力。控制結構 (Control Structures) 是程式的靈魂,它決定了程式碼執行的順序與邏輯。

本章將帶您深入 Python 的流程控制世界,從基礎的條件判斷到 Python 3.10 引入的強大 match-case 模式比對,再到迴圈的高級控制技巧與迭代器原理。我們不僅教您「怎麼寫」,更教您「為什麼這樣寫」。

1. 邏輯決策:讓程式學會選擇

程式的核心在於根據不同情況執行不同操作。Python 使用縮排 (Indentation) 來定義程式碼區塊,這強迫了程式碼的可讀性。

1.1 條件判斷 (if-elif-else)

這是最基礎的決策結構。

age = 20
status = "student"

if age >= 18 and status == "student":
    print("享有學生票優惠")
elif age >= 65:
    print("享有敬老票優惠")
else:
    print("請購買全票")

巢狀條件與扁平化 (Flat is better than nested)

過度巢狀的 if 會導致「波動拳」程式碼 (Hadouken Code),難以閱讀。

Yes
Yes
Yes
開始
條件 A?
條件 B?
條件 C?
執行動作

👎 巢狀寫法 (Bad):

if user.is_active:
    if user.has_permission:
        if resource.is_available:
            access_resource()

👍 扁平寫法 (Good - Guard Clause):

if not user.is_active:
    return
if not user.has_permission:
    return
if not resource.is_available:
    return

access_resource()

1.2 結構化模式比對 (Structural Pattern Matching)

Python 3.10 引入了 match-case,這不只是 switch-case 的語法糖,而是強大的解構工具。

# 傳統寫法可能是好幾個 if-elif
http_status = 404

match http_status:
    case 200:
        print("請求成功")
    case 400 | 404:  # 多重條件
        print("客戶端錯誤")
    case 500 | 501:
        print("伺服器錯誤")
    case _:  # 預設情況 (Wildcard)
        print("未知狀態碼")

進階解構比對

match-case 可以直接拆解數據結構,這是 if 難以做到的。

command = ["quit"]

match command:
    case ["quit"]:
        print("程式結束")
    case ["load", filename]:  # 自動將第二個元素綁定到 filename
        print(f"正在讀取檔案: {filename}")
    case ["save", filename, *options]: # 支援解包 (Unpacking)
        print(f"儲存 {filename},選項: {options}")
    case _:
        print("無效指令")

2. 迴圈控制:重複的力量

迴圈讓電腦發揮其最擅長的優勢:不知疲倦地重複執行。

2.1 For 迴圈與可迭代物件 (Iterables)

for 迴圈在 Python 中是透過「迭代器協定 (Iterator Protocol)」運作的,這意味著它可以遍歷任何「可迭代」的物件(如列表、字串、字典、檔案)。

# 遍歷字典
user_scores = {"Alice": 90, "Bob": 85, "Charlie": 95}

for name, score in user_scores.items():
    print(f"{name}: {score}")

Range 函數的奧秘

range() 產生的不是列表,而是一個惰性 (Lazy) 的可迭代序列,這在處理大範圍數字時極其節省記憶體。

# 記憶體效率高,不會真的產生 0 到 100萬 的列表
for i in range(0, 1000000, 2):
    if i > 5:
        break
    print(i)

2.2 While 迴圈

當我們不知道確切的迭代次數,只知道停止條件時,使用 while

import random

target = 5
guess = 0

while guess != target:
    guess = random.randint(1, 10)
    print(f"猜測: {guess}")
    
print("猜中了!")

2.3 迴圈控制指令

指令描述場景
break強制跳出當前迴圈找到目標後立即停止
continue跳過本次迭代,直接進入下一次過濾無效數據
pass不做任何事 (佔位符)尚未實作的程式碼區塊
else當迴圈正常結束 (未被 break) 時執行搜尋失敗後的處理

鮮為人知的 for-else 語法

這是 Python 特有的語法,常用於搜尋場景。

numbers = [1, 3, 5, 7]

for num in numbers:
    if num % 2 == 0:
        print("找到偶數!")
        break
else:
    # 只有當迴圈完整跑完且沒有執行 break 時才會執行
    print("沒有找到任何偶數")

3. 深入理解:迭代器 (Iterator) 與生成器 (Generator)

理解迭代器是晉升 Python 高手的關鍵。

可迭代 (Iterable) vs 迭代器 (Iterator)

  • Iterable: 具有 __iter__ 方法的物件(如 list, str)。可以被 for 迴圈使用。
  • Iterator: 具有 __next__ 方法的物件。負責記住目前的位置並產生下一個值。
Syntax error in textmermaid version 10.9.5

生成器 (Generator)

生成器是一種簡易的迭代器寫法,使用 yield 關鍵字。它允許我們撰寫記憶體效率極高的大量數據處理程式。

def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a  # 暫停執行並回傳值
        a, b = b, a + b

# 使用生成器
for num in fibonacci(10):
    print(num, end=" ")

4. 最佳實踐:Pythonic 的流程控制

4.1 使用 enumerate 取代 range(len())

當需要同時取得索引和值時:

👎 不推薦:

fruits = ["apple", "banana"]
for i in range(len(fruits)):
    print(i, fruits[i])

👍 推薦:

for i, fruit in enumerate(fruits):
    print(i, fruit)

4.2 列表推導式 (List Comprehension)

對於簡單的轉換邏輯,列表推導式比 for 迴圈更簡潔且通常更快。

# 傳統寫法
squares = []
for x in range(10):
    if x % 2 == 0:
        squares.append(x**2)

# 推導式寫法
squares = [x**2 for x in range(10) if x % 2 == 0]

4.3 賦值表達式 (Walrus Operator :=)

Python 3.8+ 引入,能在表達式中同時賦值與回傳。

# 讀取檔案直到空行為止
while (line := file.readline()) != "":
    print(line.strip())

5. 常見問題 (FAQ)

Q1: switch 語句在哪裡?

A: Python 在 3.10 之前沒有 switch,通常使用 if-elif-else 或字典映射 (dict.get) 來取代。3.10 之後請使用強大的 match-case

Q2: 為什麼修改列表時不建議使用 for 迴圈?

A: 在迭代列表時同時修改它(如 remove 元素)會導致索引錯亂,產生預期外的結果。建議迭代列表的副本 (for item in list[:]) 或使用列表推導式建立新列表。

Q3: break 可以跳出多層巢狀迴圈嗎?

A: 不能。break 只能跳出最近的一層迴圈。若需跳出多層,建議將巢狀迴圈封裝成函數並使用 return,或使用例外處理機制。

6. 總結

流程控制是賦予程式邏輯的核心。掌握好條件判斷與迴圈,您就能撰寫出處理複雜邏輯的程式。

本章重點回顧:

  • Flatten logic: 優先使用 Guard Clauses 減少巢狀 if
  • Match-Case: 善用 Python 3.10+ 的模式比對處理複雜條件。
  • Iterator Protocol: 理解 for 迴圈背後的迭代器機制。
  • Pythonic Style: 使用 enumerate, zip, list comprehension 讓程式碼更優雅。

在下一章中,我們將學習 函數 (Functions),這是模組化程式設計的基石,讓我們能將重複的邏輯封裝並重複利用!


延伸閱讀

LATEST POST
TAG