生成器表達式:Python中比列表推導式更省內存的寫法

你有沒有遇到過這樣的情況:想從大量數據中計算結果,結果列表一創建就“撐爆”了內存?比如生成一個包含100萬個元素的列表,Python會把所有元素都存在內存裏,這時候如果數據量再大一點,內存可能就不夠用了。

今天我們就來聊聊Python中一個更省內存的寫法——生成器表達式,它能完美解決列表推導式的內存佔用問題。

先說說列表推導式的“內存包袱”

列表推導式是Python中很常用的創建列表的方式,語法像這樣:

# 列表推導式:計算1到10的平方,返回一個列表
squares = [x**2 for x in range(10)]
print(squares)  # 輸出:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

列表推導式的特點是一次性生成所有結果,把它們都存到一個列表裏。但如果我們要處理的數據量很大(比如100萬、1000萬甚至更多),這個列表就會像一個裝滿蘋果的大箱子,把所有元素都“塞”進內存,導致內存佔用飆升。

舉個例子:如果我們想計算1到100萬的平方,列表推導式會生成一個包含100萬個數字的列表,每個數字都佔用內存空間。如果數據量繼續增大,內存很快就會被“撐爆”。

生成器表達式:只“用”不“存”的小技巧

生成器表達式是列表推導式的“輕量化”版本,寫法上和列表推導式幾乎一樣,只是把方括號 [] 換成了圓括號 ()

# 生成器表達式:計算1到10的平方,返回一個生成器對象
squares_gen = (x**2 for x in range(10))
print(squares_gen)  # 輸出:<generator object <genexpr> at 0x...>

生成器表達式的核心優勢是惰性計算(也叫“延遲計算”):它不會一次性把所有結果都算出來存起來,而是需要的時候才生成一個元素,用完就“丟棄”,只保留當前需要處理的元素。

想象一下,列表推導式是“把所有蘋果都裝在一個大箱子裏”,而生成器表達式是“每次只拿一個蘋果,用完就放回箱子”——內存裏永遠只需要存一個蘋果(當前元素),而不是一箱子蘋果。

生成器表達式怎麼用?

生成器表達式本身是一個“生成器對象”,它可以直接用在 for 循環中迭代,也可以用 next() 函數手動獲取下一個元素。

1. 直接用在for循環中迭代

squares_gen = (x**2 for x in range(10))
for num in squares_gen:
    print(num, end=' ')  # 輸出:0 1 4 9 16 25 36 49 64 81

每次循環時,生成器會生成下一個元素,循環結束後,生成器就“空了”(沒有更多元素了)。

2. 用next()函數手動獲取元素

如果想手動控制生成器的“進度”,可以用 next() 函數:

squares_gen = (x**2 for x in range(5))
print(next(squares_gen))  # 輸出:0
print(next(squares_gen))  # 輸出:1
print(next(squares_gen))  # 輸出:4
print(next(squares_gen))  # 輸出:9
print(next(squares_gen))  # 輸出:16
print(next(squares_gen))  # 報錯:StopIteration(沒有更多元素了)

每次調用 next(),生成器都會“前進”一個元素,直到所有元素都被取出後,再調用 next() 就會拋出 StopIteration 錯誤。

生成器表達式 vs 列表推導式:誰更省內存?

特性 列表推導式([]) 生成器表達式(())
內存佔用 一次性存儲所有元素 只存儲當前生成的元素
計算時機 立即生成所有結果 需要時才生成(惰性計算)
生成的數據類型 列表(list) 生成器(generator)
重複使用 可以多次訪問列表中的元素 生成器只能迭代一次(用完即空)

核心結論:當處理大數據(比如10萬、100萬甚至更多元素),或者只需要逐個處理元素(不需要保存所有結果)時,生成器表達式的內存佔用會遠小於列表推導式。

什麼時候用生成器表達式?

  1. 處理大數據集:比如統計日誌文件中的某類數據,不需要把所有行都存起來,逐行處理即可。
  2. 只需要迭代一次:比如計算列表中所有偶數的和,處理完一個就丟棄一個,不需要保留所有結果。
  3. 模擬無限序列:Python中列表無法表示無限序列(會內存溢出),但生成器可以“生成”無限個元素(比如斐波那契數列),只需要在循環中設置終止條件。

總結

生成器表達式是Python中優化內存的利器,它用圓括號 () 代替列表的方括號 [],通過惰性計算避免了一次性存儲所有元素,大大節省了內存佔用。

如果你需要處理大量數據或只需要逐個迭代元素,生成器表達式會是比列表推導式更高效的選擇。記住它的核心:“用一個,算一個,不佔內存存所有”

現在,試着把你常用的列表推導式改成生成器表達式吧,體驗一下內存“瘦身”的快樂!

小夜