這部分理解起來比較費(fèi)勁拟糕,多練習(xí)判呕,多思考~
一 生成器
我們知道列表的大小是有限制的倦踢,假設(shè)我們要放自然數(shù)0~100萬,那這個(gè)列表肯定占了很大內(nèi)存空間佛玄,而且我們也可能只用到其中很小一部分的數(shù)據(jù)硼一,這樣的話我們用列表造成的浪費(fèi)就很大了累澡。但是梦抢,如果這個(gè)列表的元素是有規(guī)律可循的,那我們就可以根據(jù)這個(gè)規(guī)律愧哟,推算到任何一個(gè)元素奥吩,不必創(chuàng)建完整的list,從而節(jié)省大量的空間蕊梧。在Python里霞赫,這種一邊循環(huán)一邊計(jì)算的機(jī)制,稱為生成器generator肥矢。
- 第一種簡(jiǎn)單的generator端衰,是把列表生成式的[ ] 改成()即可
L = [i * i for i in range(1,11) if i%2==0]
print(L) # [4, 16, 36, 64, 100]
g=(i * i for i in range(1,11) if i%2==0)
print(g) # <generator object <genexpr> at 0x000002D6BDBADBF8>
通過next(g)可以打印出generator中的元素:
print(next(g)) #4
print(next(g)) #16
print(next(g)) #36
print(next(g)) #64
print(next(g)) #100
# print(next(g)) #StopIteration 沒有足夠的元素,調(diào)用next會(huì)拋出StopIteration甘改。
當(dāng)然更簡(jiǎn)單的是通過for循環(huán)遍歷generator,同時(shí)還防止了StopIteration:
g=(i * i for i in range(1,11) if i%2==0)
for i in g:
print(i)
輸出:
4
16
36
64
100
能用for遍歷旅东,說明generator是個(gè)可迭代對(duì)象。
- 當(dāng)規(guī)律更復(fù)雜十艾,不能用列表生成式那樣簡(jiǎn)單生成抵代,可以用帶yield 的函數(shù)來生成。一旦函數(shù)帶了yield 關(guān)鍵字忘嫉,那這個(gè)函數(shù)就不是通常的函數(shù)了荤牍,而是generator。
def func():
print('step 1')
yield 1
print('step 2')
yield (2)
print('step 3')
yield (3)
f=func()
print(next(f))
print(next(f))
print(next(f))
看下輸出庆冕,分析下結(jié)果:
step 1
1
step 2
2
step 3
3
第一次執(zhí)行next(f)康吵,函數(shù)內(nèi)部打印了 step 1,再執(zhí)行了 yield 1访递。而且這個(gè)1晦嵌,整好被我們print打印出來了。也就是說next(f)返回了1力九,結(jié)果上類似于return 1 了耍铜,此時(shí)函數(shù)終止在這里。
第二次執(zhí)行next(f)跌前,函數(shù)繼續(xù)往下走棕兼,先打印step 2,再執(zhí)行yield (2)抵乓,函數(shù)終止伴挚,返回 2靶衍,并打印肩钠。
第三次執(zhí)行next(f)腕侄,函數(shù)繼續(xù)往下走槽驶,先打印step 3吁朦,再執(zhí)行yield (3)箫柳,函數(shù)終止涛目,返回 3欺矫,并打印沈跨。
可以得出結(jié)論:帶yield的generator偷厦,遇到y(tǒng)ield函數(shù)終止商叹,并返回相應(yīng)的值。這就是規(guī)則只泼。
等同于用for來遍歷:
f=func()
for i in f:
print(i)
運(yùn)行結(jié)果完全一樣剖笙。
好像有點(diǎn)亂~對(duì)于一個(gè)generator來說,用for遍歷的效果等同于不停的調(diào)用next(忽略異常)请唱。
到這里弥咪,我們只需要清楚生成器是什么(一邊循環(huán)一邊計(jì)算的機(jī)制),他的兩種常見形式十绑,如何打印元素聚至,執(zhí)行流程即可。
二 迭代器
像上面講到的generator孽惰,可以被next()函數(shù)調(diào)用并不斷返回下一個(gè)值的對(duì)象稱為迭代器:Iterator晚岭。
除此之外,像集合數(shù)據(jù)類型勋功,如list坦报、tuple、dict狂鞋、set片择、str等,可以直接作用于for循環(huán)的對(duì)象統(tǒng)稱為可迭代對(duì)象:Iterable骚揍。generator也可以直接作用于for字管,所以generator同時(shí)也是Iterable。
生成器都是Iterator對(duì)象信不,但list嘲叔、dict、str雖然是Iterable抽活,卻不是Iterator硫戈。因?yàn)镻ython的Iterator對(duì)象表示的是一個(gè)數(shù)據(jù)流,通過next()函數(shù)調(diào)用并不斷返回下一個(gè)數(shù)據(jù)下硕。所以可以把他看成一個(gè)有序的丁逝,未知大小的序列汁胆,可以看成無限大,而我們常見的集合型對(duì)象都是有限大小的霜幼。