本文 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。 |
最佳實踐
- 保持單行簡潔:每個生成式盡量不超過 80 個字元;必要時可使用圓括號分行。
- 使用
enumerate、zip:取代手動索引,提高可讀性。 - 善用
any、all:配合生成式快速判斷條件。has_even = any(x % 2 == 0 for x in numbers) all_positive = all(x > 0 for x in numbers) - 搭配
map、filter:在需要懶評估且不想寫if時可考慮。 - 測試邊界:對空集合、負數、非可迭代物件加上例外處理,避免執行時錯誤。
實際應用場景
| 場景 | 為何使用生成式 |
|---|---|
| 資料前處理 | 快速清理 CSV 中的缺失值、轉換型別。 |
| API 回傳 | 把資料庫查詢結果直接轉成 JSON 需要的字典結構。 |
| 演算法實作 | 例如 BFS、DFS 中的鄰接表生成、或是圖的邊集合。 |
| 機器學習特徵工程 | 把文字切割成 n-gram、或是把特徵向量轉成稀疏集合。 |
| 日誌分析 | 從大量日誌檔中抽取特定關鍵字或時間戳記。 |
範例:將資料庫查詢結果轉成 API JSON
假設rows為[(id, name, score), ...],我們只想回傳id與score,且把score四捨五入至小數點第二位:
api_data = [{ "id": r[0], "score": round(r[2], 2) } for r in rows]
總結
- 列表、集合、字典生成式 是 Python 中最常用的「一行解決多步驟」技巧,能大幅減少樣板程式碼。
- 透過 條件過濾、巢狀迭代 以及 函式抽象,我們可以在保持可讀性的前提下完成複雜的資料轉換。
- 使用時要留意 記憶體消耗、可讀性 與 鍵值衝突 等常見陷阱,並遵循 最佳實踐(適度分行、善用
enumerate/zip、必要時改用 generator)。 - 在實務專案中,生成式常見於 資料前處理、API 格式化、演算法實作 等場景,是提升開發效率的利器。
掌握了這些概念與技巧,你就能在 Python 程式碼中寫出更簡潔、高效且易於維護的邏輯,為日後的開發奠定堅實基礎。祝你在程式之路上玩得開心、寫得順手!