迭代器協(xié)議
1.迭代器協(xié)議是指:對象必須提供一個(gè)next方法薛闪,執(zhí)行該方法要么返回迭代中的下一項(xiàng)辛馆,要么就引起一個(gè)StopIteration異常,以終止迭代 (只能往后走不能往前退)
2.可迭代對象:實(shí)現(xiàn)了迭代器協(xié)議的對象(如何實(shí)現(xiàn):對象內(nèi)部定義一個(gè)__iter__()方法)
3.協(xié)議是一種約定豁延,可迭代對象實(shí)現(xiàn)了迭代器協(xié)議昙篙,python的內(nèi)部工具(如for循環(huán),sum诱咏,min苔可,max函數(shù)等)使用迭代器協(xié)議訪問對象。
for 循環(huán)機(jī)制
for循環(huán)的本質(zhì):循環(huán)所有對象袋狞,全都是使用迭代器協(xié)議焚辅。
for循環(huán)就是基于迭代器協(xié)議提供了一個(gè)統(tǒng)一的可以遍歷所有對象的方法,即在遍歷之前苟鸯,先調(diào)用對象的__iter__方法將其轉(zhuǎn)換成一個(gè)迭代器同蜻,然后使用迭代器協(xié)議去實(shí)現(xiàn)循環(huán)訪問,這樣所有的對象就都可以通過for循環(huán)來遍歷了早处,
列表湾蔓,字符串,元組砌梆,字典默责,集合,文件對象等本質(zhì)上來說都不是可迭代對象么库,在使用for循環(huán)的時(shí)候內(nèi)部是先調(diào)用他們內(nèi)部的_iter_方法傻丝,使他們變成了可迭代對象,然后在使用可迭代對象的_next_方法依次循環(huán)元素诉儒,當(dāng)元素循環(huán)完時(shí),會觸發(fā)StopIteration異常亏掀,for循環(huán)會捕捉到這種異常忱反,終止迭代
#迭代器協(xié)議訪問
li =[1,2,3,4]
f =
li.__iter__()#第一步泛释,先通過內(nèi)部的_iter_方法,先把對象變成可迭代對象
print(f.__next__())#對可迭代對象用_next_方法取值
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())#StopIteration,超出邊界會報(bào)錯
#for循環(huán)訪問
#for循環(huán)的本質(zhì)就是遵循迭代器協(xié)議的訪問方式,先調(diào)用iter_i=i.__iter__()方法,或者直接iter_i=iter(l),然后依次執(zhí)行iter_i.next(),直到for循環(huán)捕捉到StopIteration終止循環(huán)
li =[1,2,3,4]
for i inli:#li_iter = li._iter_()
???print(i)#li_iter._next_
#用while去模擬for循環(huán)做的事情
iter_i=i.__iter__()
while True:
??? try:
??????? print(iter_i.__next__())
??? except StopIteration:
??????? print('迭代完畢了,循環(huán)終止了')
??????? break
生成器
生成器類似于一種數(shù)據(jù)類型温算,這種數(shù)據(jù)類型自動實(shí)現(xiàn)了迭代器協(xié)議(其他的數(shù)據(jù)類型需要調(diào)用自己內(nèi)置的__iter__方法)怜校,所以生成器就是可迭代對象
生成器分類及在python中的表現(xiàn)形式:(Python有兩種不同的方式提供生成器)
1.生成器函數(shù):常規(guī)函數(shù)定義,但是注竿,使用yield語句而不是return語句返回結(jié)果茄茁。yield語句一次返回一個(gè)結(jié)果,在每個(gè)結(jié)果中間巩割,掛起函數(shù)的狀態(tài)裙顽,以便下次重它離開的地方繼續(xù)執(zhí)行
2.生成器表達(dá)式:類似于列表推導(dǎo),但是宣谈,生成器返回按需產(chǎn)生結(jié)果的一個(gè)對象愈犹,而不是一次構(gòu)建一個(gè)結(jié)果列表,按需取出對象
為何使用生成器之生成器的優(yōu)點(diǎn)
Python使用生成器對延遲操作提供了支持闻丑。所謂延遲操作漩怎,是指在需要的時(shí)候才產(chǎn)生結(jié)果,而不是立即產(chǎn)生結(jié)果嗦嗡。這也是生成器的主要好處勋锤。
三元表達(dá)式:? f=result =值1 if 條件 else 值2
列表解析:s = [三元表達(dá)式],列表解析生成的是一個(gè)真實(shí)存在于內(nèi)存中的列表,對于比較大的列表侥祭,比較耗內(nèi)存空間
count=[x for
x in range(3)]#列表解析
count=(x for x in range(3))#生成器本身就是迭代器怪得,遵循迭代器協(xié)議
生成器表達(dá)式2:yield函數(shù),生成器使用yield語句返回一個(gè)值卑硫。yield語句掛起該生成器函數(shù)的狀態(tài)徒恋,保留足夠的信息,以便之后從它離開的地方繼續(xù)執(zhí)行
send():可對yield函數(shù)傳參數(shù)欢伏,參數(shù)會賦值給yield函數(shù)前的變量入挣,通過send()可實(shí)現(xiàn)偽并發(fā)功能
def count():
??? print(1)
??? yield ("a")#相當(dāng)于return,不同于return,yield可以返回多個(gè)值
??? print(2)
??? yield ("b")
f=count()
print(f.__next__())#保留當(dāng)前執(zhí)行狀態(tài)硝拧,下次執(zhí)行從上次狀態(tài)處繼續(xù)往下執(zhí)行
print(f.__next__())
print(f.__next__())#執(zhí)行只能一直往前走径筏,不能往后,只能執(zhí)行一次障陶,執(zhí)行完繼續(xù)執(zhí)行會觸發(fā)StopIteration
#偽并發(fā)
import time#導(dǎo)入時(shí)間模塊
defguke(name):
??? print("我是%s,我準(zhǔn)備吃包子了"%name)
??? while True:
??????? baozi = yield
??????? time.sleep(1)
???? ???print("我是%s,我把包子%s吃掉了"%(name,baozi))
defshengchanzhe(x):
??? xiaofeizhe = guke(x)
??? xiaofeizhe.__next__()
??? for i in range(100):
??????? time.sleep(1)
??????? xiaofeizhe.send(i)#將i賦值給guke()函數(shù)中yield前面的包子滋恬,下次執(zhí)行時(shí)從此往后執(zhí)行
use_name =
input("歡迎您!怎么稱呼您:")
print("請稍等抱究!包子馬上就給您端上來")
shengchanzhe(use_name)
# 生成器只能遍歷一次
defget_province_population(filename):
??? with open(filename) as f:
??????? for line in f:
??????????? yield int(line)
gen =get_province_population('data.txt')
print(gen)
all_population= sum(gen)
print(all_population)
forpopulation in gen:
??? print(population / all_population)
執(zhí)行上面這段代碼恢氯,將不會有任何輸出,這是因?yàn)椋善髦荒鼙闅v一次勋拟。
生成器總結(jié):
1.語法上和函數(shù)類似:生成器函數(shù)和常規(guī)函數(shù)幾乎是一樣的勋磕。它們都是使用def語句進(jìn)行定義,差別在于
生成器使用yield語句返回一個(gè)值敢靡,而常規(guī)函數(shù)使用return語句返回一個(gè)值
2.自動實(shí)現(xiàn)迭代器協(xié)議:由于生成器自動實(shí)現(xiàn)了迭代器協(xié)議挂滓,所以我們可以調(diào)用它的next方法,并且啸胧,在沒有值可以返回的時(shí)候赶站,生成器自動產(chǎn)生StopIteration異常
3.狀態(tài)掛起:生成器使用yield語句返回一個(gè)值。yield語句掛起該生成器的狀態(tài)纺念,保留足夠的信息贝椿,以便之后從它離開的地方繼續(xù)執(zhí)行。
4.生成器只能遍歷一次柠辞,不能重復(fù)使用:在程序中如果已經(jīng)使用生成器遍歷過一次得到結(jié)果团秽,那么第二次遍歷生成器將得不到任何結(jié)果,因?yàn)樵诘谝淮伪闅v生成器時(shí)叭首,生成器已經(jīng)遍歷到頭习勤,它的特性決定它無法遍歷第二次。
總結(jié):
? ? ? ? 1.生成器就是特殊的迭代器焙格,它在迭代器的基礎(chǔ)上再次進(jìn)行了封裝图毕,生成器是協(xié)程的基礎(chǔ),協(xié)程是通過上下文切換進(jìn)行任務(wù)協(xié)作的眷唉,而生成器掛起狀態(tài)的特性很好地滿足了協(xié)程的需求;
? ? ? ? 2.凡是可以被for循環(huán)訪問的都是迭代器予颤,這是因?yàn)榈骼锩鎸?shí)現(xiàn)了iter協(xié)議和next方法;