本文 AI 產出,尚未審核

Python 課程 – 控制流程(Control Flow)

主題:comprehension(列表、集合、字典生成式)


簡介

在日常開發中,我們常需要從一組資料中挑選、轉換或重組成新的容器。傳統的做法是使用 for 迴圈逐一處理,程式碼往往冗長且不易閱讀。Python 的 comprehension(生成式) 以簡潔的語法一次完成迭代、條件篩選與值的計算,讓程式碼更具表達力,也更符合「Pythonic」的寫作風格。

掌握列表、集合與字典生成式,不僅能提升開發效率,還能在資料前處理、演算法實作以及 API 回傳格式等情境中,寫出更易維護的程式。本文將從概念說明、實作範例、常見陷阱到最佳實踐,帶你一步步深入了解這項重要技巧。


核心概念

1. 列表生成式(List Comprehension)

列表生成式的基本語法是:

[ <表達式> for <變數> in <可迭代物件> if <條件> ]
  • <表達式>:決定產生的元素值,常用來做運算或呼叫函式。
  • for <變數> in <可迭代物件>:遍歷來源資料。
  • if <條件>(可選):只保留符合條件的元素。

範例 1:平方數列表

# 產生 0~9 的平方數
squares = [x**2 for x in range(10)]
print(squares)   # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

註解x**2 為表達式,range(10) 為可迭代物件。

範例 2:條件篩選

# 只保留偶數的平方
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares)   # [0, 4, 16, 36, 64]

範例 3:字串處理

words = ["Python", "程式設計", "AI", "資料科學"]
# 產生所有字串的長度
lengths = [len(w) for w in words]
print(lengths)   # [6, 5, 2, 5]

2. 集合生成式(Set Comprehension)

集合生成式的語法與列表相同,只是把方括號 [] 換成大括號 {},結果會自動去除重複元素,且無序。

{ <表達式> for <變數> in <可迭代物件> if <條件> }

範例 4:取得唯一的字元

sentence = "Python程式設計語言"
unique_chars = {c for c in sentence}
print(unique_chars)
# 可能輸出:{'程', '設', 'P', 'y', 't', 'h', 'n', '語', '言', '程', '式', '設', '計'}

重點:集合會自動去除重複的字元。

範例 5:篩選質數集合

def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n**0.5)+1):
        if n % i == 0:
            return False
    return True

primes = {x for x in range(2, 50) if is_prime(x)}
print(primes)   # {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47}

3. 字典生成式(Dict Comprehension)

字典生成式允許同時產生鍵和值,語法為:

{ <鍵表達式> : <值表達式> for <變數> in <可迭代物件> if <條件> }

範例 6:字母對應其 ASCII 碼

ascii_map = {c: ord(c) for c in "ABCDEF"}
print(ascii_map)   # {'A': 65, 'B': 66, 'C': 67, 'D': 68, 'E': 69, 'F': 70}

範例 7:統計字串中每個字元出現次數

text = "banana"
freq = {c: text.count(c) for c in set(text)}
print(freq)   # {'b': 1, 'a': 3, 'n': 2}

說明:先把 text 轉成集合去除重複,再計算每個字元的次數。


4. 巢狀生成式(Nested Comprehension)

當需要多層迭代時,生成式同樣支援巢狀寫法,語法仍保持單行。

範例 8:矩陣轉置(二維列表)

matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

# 透過巢狀列表生成式完成轉置
transpose = [[row[i] for row in matrix] for i in range(3)]
print(transpose)
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

範例 9:展開平面座標組合

xs = [0, 1, 2]
ys = [10, 20]

points = [(x, y) for x in xs for y in ys]
print(points)   # [(0, 10), (0, 20), (1, 10), (1, 20), (2, 10), (2, 20)]

常見陷阱與最佳實踐

陷阱 說明 建議的解決方式
過度巢狀 生成式層數過多(>2)會使可讀性下降。 若超過兩層,考慮拆成普通 for 迴圈或使用 itertools.product
大量資料 生成式一次性產生全部元素,記憶體需求可能過大。 使用 generator expression(expr for ...))配合 list()set()dict() 逐步消費。
條件寫錯 if 放錯位置會改變過濾邏輯。 確認 if 只在最後,且只影響 表達式 的輸出,而非迭代本身。
可讀性 內嵌函式或過長表達式會讓人難以理解。 把複雜運算抽成小函式,或在生成式外先定義變數。
鍵值衝突(字典) 同一鍵在迭代中多次出現,後者會覆蓋前者。 若需要保留所有值,改用 defaultdict(list)setdefault

最佳實踐

  1. 保持單行簡潔:每個生成式盡量不超過 80 個字元;必要時可使用圓括號分行。
  2. 使用 enumeratezip:取代手動索引,提高可讀性。
  3. 善用 anyall:配合生成式快速判斷條件。
    has_even = any(x % 2 == 0 for x in numbers)
    all_positive = all(x > 0 for x in numbers)
    
  4. 搭配 mapfilter:在需要懶評估且不想寫 if 時可考慮。
  5. 測試邊界:對空集合、負數、非可迭代物件加上例外處理,避免執行時錯誤。

實際應用場景

場景 為何使用生成式
資料前處理 快速清理 CSV 中的缺失值、轉換型別。
API 回傳 把資料庫查詢結果直接轉成 JSON 需要的字典結構。
演算法實作 例如 BFS、DFS 中的鄰接表生成、或是圖的邊集合。
機器學習特徵工程 把文字切割成 n-gram、或是把特徵向量轉成稀疏集合。
日誌分析 從大量日誌檔中抽取特定關鍵字或時間戳記。

範例:將資料庫查詢結果轉成 API JSON
假設 rows[(id, name, score), ...],我們只想回傳 idscore,且把 score 四捨五入至小數點第二位:

api_data = [{ "id": r[0], "score": round(r[2], 2) } for r in rows]

總結

  • 列表、集合、字典生成式 是 Python 中最常用的「一行解決多步驟」技巧,能大幅減少樣板程式碼。
  • 透過 條件過濾巢狀迭代 以及 函式抽象,我們可以在保持可讀性的前提下完成複雜的資料轉換。
  • 使用時要留意 記憶體消耗可讀性鍵值衝突 等常見陷阱,並遵循 最佳實踐(適度分行、善用 enumerate/zip、必要時改用 generator)。
  • 在實務專案中,生成式常見於 資料前處理、API 格式化、演算法實作 等場景,是提升開發效率的利器。

掌握了這些概念與技巧,你就能在 Python 程式碼中寫出更簡潔高效易於維護的邏輯,為日後的開發奠定堅實基礎。祝你在程式之路上玩得開心、寫得順手!