編者注:本文主要參考了《Python核心編程(第二版)》
說到生成器,先說說列表解析。列表解析可以動態創建列表。
[expr for iter_var in iterable if cond_expr]
該句的核心是 for循環,它迭代了iterable對象的所有條目。如果滿足cond_expr(條件表達式),則前面的expr(表達式)應用於該成員。最后生成的是滿足條件的元素的該表達式的列表。對於lambda,map(),filter()等可以通過列表解析簡化為一個列表解析式。 首先看看這三個函數的作用:
map(lambda x:x**2, range(6)) >>>[0, 1, 4, 9, 16, 25]
lambda 輸入參數:輸出表達式 允許創建一行函數對象,不用def定義,簡化代碼
map(操作,需要操作的列表) 對所有列表成員應用一個操作
可以用列表解析來簡化上面的操作:
[x**2 for x in range(6)] >>>[0, 1, 4, 9, 16, 25]
同樣也可以用列表解析來簡化filter()操作,比如:
seq = [11, 10, 1, 9, 10, 2, 3, 44, 12, 11] print filter(lambda x: x % 2, seq) >>>[11, 1, 9, 3, 11]
可以用列表解析來簡化上面的操作:
print [x for x in seq if x % 2] >>>[11, 1, 9, 3, 11]
生成器是列表解析的一個拓展。
(expr for iter_var in iterable if cond_expr)
它與列表解析器非常相似,且語法基本相同,但不是真正創建列表而是生成一個生成器。這個生成器在每次計算出一個條目后,把這個條目“產生(yield)出來”,生成器表達式使用了“延遲計算(lazy evaluation)”,所以它使用內存上更有效。
print (x for x in seq if x % 2) >>><generator object <genexpr> at 0x00000000025B6AB0>
那到底什么時候使用生成器呢?
當創建列表只是一共中間過程的時候,為了避免創建龐大的列表,我們可以使用生成器表達式來完成。比如,我們要計算一篇txt文本的單詞數時,我們沒必要先將列表生成再計算單詞數。
f = open('*.txt','r') len([word for line in f for word in line.split()]) #使用列表解析,先生成列表后計數 len(word for line in f for word in line.split()) #使用生成器,對返回的生成器計數,沒有生成列表
所做的只是把方括號去掉,不但少了兩個字節,更節省了內存。
這讓我想起了使用xrange()代替range(),道理是一樣的。xrange返回一個生成器,而range返回一個列表。