https://www.cnblogs.com/yuanchenqi/articles/5769491.html
https://www.cnblogs.com/yyds/p/6281453.html
列表生成式:顧名思義,列表生成式就是一個(gè)用來生成列表的特定語法形式的表達(dá)式婆誓。
基礎(chǔ)語法格式
[exp for iter_var in iterable]
生成器與列表生成式對(duì)比
既然通過列表生成式就可以直接創(chuàng)建一個(gè)新的list捞蛋,那么為什么還要有生成器存在呢?
因?yàn)榱斜砩墒绞侵苯觿?chuàng)建一個(gè)新的list尊惰,它會(huì)一次性地把所有數(shù)據(jù)都存放到內(nèi)存中讲竿,這會(huì)存在以下幾個(gè)問題:
內(nèi)存容量有限,因此列表容量是有限的弄屡;
當(dāng)列表中的數(shù)據(jù)量很大時(shí)题禀,會(huì)占用大量的內(nèi)存空間,如果我們僅僅需要訪問前面有限個(gè)元素時(shí)膀捷,就會(huì)造成內(nèi)存資源的極大浪費(fèi)迈嘹;
當(dāng)數(shù)據(jù)量很大時(shí),列表生成式的返回時(shí)間會(huì)很慢全庸;
而生成器中的元素是按照指定的算法推算出來的秀仲,只有調(diào)用時(shí)才生成相應(yīng)的數(shù)據(jù)。這樣就不必一次性地把所有數(shù)據(jù)都生成壶笼,從而節(jié)省了大量的內(nèi)存空間神僵,這使得其生成的元素個(gè)數(shù)幾乎是沒有限制的,并且操作的返回時(shí)間也是非掣才快速的(僅僅是創(chuàng)建一個(gè)變量而已)保礼。
例如:s=(x*2 for x in range(100)#range(start, stop[, step]),o開始
print(next(s))#等價(jià)于s.next() in py2: s.next() 結(jié)果為0;
print(next(s))#等價(jià)于s.next() in py2: s.next() 結(jié)果為4责语;
生成器(Generator)
生成器就是可迭代對(duì)象炮障;本質(zhì)就是一個(gè)函數(shù)
從名字上來看,生成器應(yīng)該是用來生成數(shù)據(jù)的坤候。
- 生成器的作用
按照某種算法不斷生成新的數(shù)據(jù)胁赢,直到滿足某一個(gè)指定的條件結(jié)束。生成器其實(shí)是一種特殊的迭代器白筹,不過這種迭代器更加優(yōu)雅徘键。 - 生成器的構(gòu)造方式
構(gòu)造生成器的兩種方式:
使用類似列表生成式的方式生成 (2*n + 1 for n in range(3, 11))
使用包含yield的函數(shù)來生成
如果計(jì)算過程比較簡(jiǎn)單,可以直接把列表生成式改成generator遍蟋;但是,如果計(jì)算過程比較復(fù)雜螟凭,就只能通過包含yield的函數(shù)來構(gòu)造generator虚青。
說明: Python 3.3之前的版本中,不允許迭代函數(shù)法中包含return語句螺男。
3. 生成器構(gòu)造實(shí)例#生成器&生成器對(duì)象指的是同一個(gè)意思棒厘,
生成器在創(chuàng)立的時(shí)候就已經(jīng)決定了能計(jì)算出的值得個(gè)數(shù)纵穿,一旦調(diào)用next的次數(shù)超出這個(gè)數(shù)量就會(huì)報(bào)錯(cuò)
1.使用類似列表生成式的方式構(gòu)造生成器
g1 = (2n + 1 for n in range(3, 6))#這是列表生成式產(chǎn)生的生成器(2n + 1 for n in range(3, 6)),還沒有產(chǎn)生數(shù)據(jù)
2.使用包含yield的函數(shù)構(gòu)造生成器
def my_range(start, end):##my_range()是生成器奢人,生成器也是函數(shù)谓媒,range是函數(shù)名
for n in range(start, end):
yield 2*n + 1 #帶有yield的生成器
g2 = my_range(3, 6)
print(type(g1))
print(type(g2))
輸出結(jié)果:
<class 'generator'>
<class 'generator'>
- 生成器的執(zhí)行過程與特性
生成器的執(zhí)行過程:
在執(zhí)行過程中,遇到y(tǒng)ield關(guān)鍵字就會(huì)中斷執(zhí)行何乎,下次調(diào)用則繼續(xù)從上次中斷的位置繼續(xù)執(zhí)行句惯。
生成器的特性:
只有在調(diào)用時(shí)才會(huì)生成相應(yīng)的數(shù)據(jù)
只記錄當(dāng)前的位置
只能next,不能prev
5. 生成器的調(diào)用方式或者方法
要調(diào)用生成器產(chǎn)生新的元素支救,有兩種方式:
調(diào)用內(nèi)置的next()方法
使用循環(huán)對(duì)生成器對(duì)象進(jìn)行遍歷(推薦)
for循環(huán)內(nèi)部做了三件事:
1.調(diào)用對(duì)象的iter方法抢野,返回一個(gè)迭代器對(duì)象
while: try: i=next (list_Iterator) except stopIteration: break
調(diào)用生成器對(duì)象的send()方法
send():
f().send(None)#等價(jià)于next(f())
s=(2*n + 1 for n in range(3, 11))
print(s)#生成器<generator object <genexpr> at 0x000001E63FFE0DD0>
print(next(s))#等價(jià)于s.next() in Py2: s.next()
print(next(s))
print(next(s))
print(next(s))#工作過程:# 迭代iterable中的每個(gè)元素;# 每次迭代都先把結(jié)果賦值給iter_var各墨,然后通過exp得到一個(gè)新的計(jì)算值指孤;# 最后把所有通過exp得到的計(jì)算值以一個(gè)新列表的形式返回。
print(next(s))
print(next(s))
print(next(s))
print(next(s))
print(next(s))#StopIteration
可見贬堵,使用next()方法遍歷生成器時(shí)恃轩,當(dāng)超出遍歷范圍,最后是以拋出一個(gè)StopIeration異常終止黎做。
實(shí)例2:使用循環(huán)遍歷生成器
g1 = (2*n + 1 for n in range(3, 6))#3,4,5
for x in g1:
print(x)
輸出結(jié)果是
7
9
11
可見叉跛,使用循環(huán)遍歷生成器時(shí)比較簡(jiǎn)潔,且最后不會(huì)拋出一個(gè)StopIeration異常引几。因此使用循環(huán)的方式遍歷生成器的方式才是被推薦的昧互。
需要說明的是:如果生成器函數(shù)有返回值,要獲取該返回值的話伟桅,只能通過在一個(gè)while循環(huán)中不斷的next()敞掘,最后通過捕獲StopIteration異常
實(shí)例3:調(diào)用生成器對(duì)象的send()方法
def my_range(start, end):
for n in range(start, end):
ret = yield 2*n + 1
print(ret)
g3 = my_range(3, 6)
print(g3.send(None))
print(g3.send('hello01'))
print(g3.send('hello02'))
輸出結(jié)果:
7
hello01
9
hello02
11
print(next(g3))
print(next(g3))
print(next(g3))
輸出結(jié)果:
7
None
9
None
11
結(jié)論:
next()會(huì)調(diào)用yield,但不給它傳值
send()會(huì)調(diào)用yield楣铁,也會(huì)給它傳值(該值將成為當(dāng)前yield表達(dá)式的結(jié)果值)
需要注意的是:第一次調(diào)用生成器的send()方法時(shí)玖雁,參數(shù)只能為None,否則會(huì)拋出異常盖腕。當(dāng)然也可以在調(diào)用send()方法之前先調(diào)用一次next()方法赫冬,目的是讓生成器先進(jìn)入yield表達(dá)式。
https://www.cnblogs.com/alex3714/articles/5143440.html
可迭代對(duì)象(Iterable)
我們經(jīng)常在Python的文檔中看到“Iterable”這個(gè)此溃列,它的意思是“可迭代對(duì)象”劲厌。那么什么是可迭代對(duì)象呢?
可直接用于for循環(huán)的對(duì)象統(tǒng)稱為可迭代對(duì)象听隐;本質(zhì)上是有iter方法的是可迭代對(duì)象(Iterable)补鼻。
滿足迭代器協(xié)議:
1.內(nèi)部有next方法
2.內(nèi)部有iter()方法
目前我們已經(jīng) 知道的可迭代(可用于for循環(huán))的數(shù)據(jù)類型有,本質(zhì)上是內(nèi)部有iter方法!!7绶丁:
li=[1,2,3]: iterable(內(nèi)部有iter方法)>>>>>>
i=iter(li):list_Iterator#i是迭代器對(duì)象
集合數(shù)據(jù)類型:如list咨跌、tuple、dict硼婿、set锌半、str等生成器(Generator)
可以使用isinstance()來判斷一個(gè)對(duì)象是否是Iterable對(duì)象:
from collections import Iterable
print(isinstance([], Iterable))