Python 資料結構:清單(list)之 List Comprehension
簡介
在 Python 中,list comprehension(清單生成式)是一種既簡潔又具表達力的語法,讓我們可以在單行程式碼內完成 迭代、條件篩選與結果組合。對於剛踏入程式設計的學員而言,掌握這項技巧不僅能減少重複的 for 迴圈,還能讓程式碼更具可讀性與維護性。
在日常開發中,從資料清理、數值運算到字串處理,幾乎每個需要「把舊資料轉成新資料」的情境,都能使用 list comprehension 以 Pythonic 的方式完成。了解其底層運作原理與常見陷阱,才能在實務上安全、有效地運用這項功能。
核心概念
1. 基本語法
最簡單的 list comprehension 形式如下:
new_list = [expression for item in iterable]
iterable:任何可迭代的物件(如list、range、str、dict等)。item:迭代過程中每一次取得的元素。expression:對item進行運算或轉換後產生的值,會依序放入new_list。
範例 1:把 1~5 的整數平方
squares = [x**2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
這段程式碼等價於
squares = [] for x in range(1, 6): squares.append(x**2)
2. 加入條件篩選
在 for 後面可以加入 if,只把符合條件的元素加入結果:
new_list = [expression for item in iterable if condition]
範例 2:篩選出 1~20 中的偶數
evens = [n for n in range(1, 21) if n % 2 == 0]
print(evens) # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
3. 多層迭代(巢狀迴圈)
list comprehension 也支援多個 for,常用於 矩陣展開 或 笛卡爾積:
new_list = [expr for x in iterable1 for y in iterable2 if condition]
範例 3:產生 3x3 的座標對
coords = [(i, j) for i in range(3) for j in range(3)]
print(coords)
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
加入條件只保留 i != j 的座標:
diag_removed = [(i, j) for i in range(3) for j in range(3) if i != j]
print(diag_removed)
# [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
4. 產生字典或集合
雖然名稱是 list comprehension,但相同的語法也可以產生 集合(set) 或 字典(dict):
# set comprehension
unique_squares = {x**2 for x in [-2, -1, 0, 1, 2]}
print(unique_squares) # {0, 1, 4}
# dict comprehension
char_cnt = {c: s.count(c) for c in set(s)}
範例 4:統計字串中每個字母出現次數
sentence = "Python is awesome"
freq = {ch: sentence.count(ch) for ch in set(sentence) if ch != ' '}
print(freq)
# {'a': 1, 'e': 2, 's': 2, 'w': 1, 'm': 1, 'P': 1, 'i': 1, 'o': 1, 't': 1, 'n': 1, 'h': 1, 'y': 1}
5. 使用函式或 lambda
在 expression 中可以直接呼叫函式,或使用 lambda 產生匿名函式,讓程式碼更具彈性:
def square(x):
return x * x
squares = [square(x) for x in range(5)]
print(squares) # [0, 1, 4, 9, 16]
範例 5:使用 lambda 把字串轉成大寫
words = ["python", "list", "comprehension"]
upper = [(lambda s: s.upper())(w) for w in words]
print(upper) # ['PYTHON', 'LIST', 'COMPREHENSION']
常見陷阱與最佳實踐
| 陷阱 | 說明 | 建議的寫法 |
|---|---|---|
| 過度複雜的表達式 | 一行寫入太多運算或條件,會降低可讀性。 | 若超過兩層 if 或運算過長,改寫成普通 for 迴圈或拆成小函式。 |
| 記憶體消耗 | List comprehension 會一次性產生完整列表,對大資料集會佔用大量記憶體。 | 使用 generator expression((expr for ...))配合 list() 或 itertools,僅在需要時才產生元素。 |
| 變數遮蔽 | 在 comprehension 中使用與外部同名的變數,會在內部覆寫。 | 盡量避免與外層作用域同名,或使用 _ 作為不需要的迭代變數。 |
誤用 if-else |
if-else 必須寫在 expression 前,否則會被解讀成條件篩選。 |
正確寫法:[a if cond else b for x in iterable],錯誤寫法:[a for x in iterable if cond else b]。 |
| 嵌套太深 | 超過三層以上的巢狀迭代,程式碼可讀性急速下降。 | 使用 itertools.product 或分段產生中間結果。 |
最佳實踐
- 保持單一目的:每個 list comprehension 應該只完成「產生」或「篩選」其中一件事。
- 使用說明性變數名稱:
num,char,row等,比x,y更易理解。 - 結合
enumerate、zip:可同時取得索引或多個序列的對應元素。
# 例:把字串列表轉成 (index, upper) 元組
items = ["apple", "banana", "cherry"]
result = [(i, s.upper()) for i, s in enumerate(items)]
print(result) # [(0, 'APPLE'), (1, 'BANANA'), (2, 'CHERRY')]
實際應用場景
資料清理
- 從 CSV 讀入的字串欄位需要去除空白、轉成數字或過濾缺失值,list comprehension 可一次完成。
raw = [" 12 ", " 7", "", " 5 "] cleaned = [int(x.strip()) for x in raw if x.strip().isdigit()] print(cleaned) # [12, 7, 5]特徵工程
- 在機器學習前,常需把類別特徵轉成 one‑hot 向量,list comprehension 讓向量化操作更直觀。
colors = ["red", "green", "blue", "red"] unique = sorted(set(colors)) one_hot = [[1 if c == col else 0 for col in unique] for c in colors] print(one_hot) # [[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 0]]API 回傳資料的重新構造
- 取得外部 API 回傳的 JSON 列表後,需要挑出特定欄位並組成新的字典列表。
users = [ {"id": 1, "name": "Alice", "age": 28}, {"id": 2, "name": "Bob", "age": 34}, {"id": 3, "name": "Cathy", "age": 22}, ] # 只保留 id 與 name simple = [{"id": u["id"], "name": u["name"]} for u in users] print(simple)圖形與視覺化
- 產生座標點或顏色映射,用於 Matplotlib、Plotly 等繪圖套件。
import matplotlib.pyplot as plt xs = [x for x in range(-10, 11)] ys = [x**2 for x in xs] # y = x^2 plt.plot(xs, ys) plt.show()
總結
List comprehension 是 Python 中 最具威力且易學 的語法之一。它讓我們能在 單行程式碼 中完成 迭代、條件篩選與資料轉換,大幅提升開發效率與程式可讀性。
- 了解基本結構
[expr for item in iterable],再逐步加入if、多層for,以及 set / dict 生成式。 - 注意避免過度複雜、記憶體浪費與變數遮蔽等常見陷阱,遵循「單一目的」與「說明性變數」的最佳實踐。
- 在資料清理、特徵工程、API 整理、圖形繪製等實務情境中,list comprehension 幾乎是 不二選擇。
掌握這項技巧後,你將能寫出更 Pythonic、更 簡潔、也更 易於維護 的程式碼。祝你在 Python 的旅程中,玩得開心、寫得順手!