2.30. 綜合運算式¶
綜合運算式 會以單一運算式,從既有的可迭代物件建構出新的 list、set、dict 或產生器。它取代了「從空容器開始、在迴圈中逐一附加」這個常見的模式。
2.30.1. list 綜合運算式¶
squares = [x * x for x in range(5)]
print(squares)
輸出:
[0, 1, 4, 9, 16]
完整寫出的相同迴圈:
squares = []
for x in range(5):
squares.append(x * x)
綜合運算式形式是一個就地建構 list 的單一運算式。沒有 squares = [],也沒有 .append -- 結果就是綜合運算式的值。
開頭的運算式產生每個項目;for 子句命名迴圈變數;可選的 if 會篩除項目。¶
2.30.2. 以 if 篩選¶
可選的 if 子句只保留符合條件的項目:
evens = [x for x in range(10) if x % 2 == 0]
print(evens)
輸出:
[0, 2, 4, 6, 8]
篩選器在開頭運算式之前執行 -- x % 2 == 0 會先被檢查;只有符合的值才會傳到 x 以產生輸出。
2.30.3. dict 與 set 綜合運算式¶
相同的形式也適用於 dict 與 set 字面值。
dict 綜合運算式 在 for 之前有一組 key: value 配對:
squares = {x: x * x for x in range(5)}
print(squares)
輸出:
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
set 綜合運算式 使用大括號與單一運算式:
unique_lengths = {len(w) for w in ["a", "bb", "c", "bb"]}
print(unique_lengths)
輸出:
{1, 2}
2.30.4. 產生器運算式¶
圓括號會產生 產生器運算式 而非 list。值會依需求一次計算一個:
total = sum(x * x for x in range(1000))
永遠不會建構出百萬項的 list。值會一個接一個地流入 sum(),由它將其相加並在過程中逐一捨棄。
當要將值餵入歸約函式(sum()、max()、any()、all())或任何其他消耗迭代器的程式碼時,產生器運算式是正確的選擇 -- 它們節省了等效 list 原本會使用的記憶體。
2.30.5. 何時不該 使用綜合運算式¶
綜合運算式簡潔,但並非總是更清楚。在以下情況請改用一般的 for 迴圈:
主體需要不只一個陳述式(綜合運算式恰好只容納一個運算式)。
主體有副作用(印出、寫入檔案)-- 綜合運算式是用來 建構 集合的,不是用來執行動作的。
篩選或轉換的部分多到讓綜合運算式不再能從左到右順讀。