從今天開始,我們將開始進入Python的難點,那就是協(xié)程。
為了寫明白協(xié)程的知識點,我查閱了網(wǎng)上的很多相關(guān)資料。發(fā)現(xiàn)很難有一個講得系統(tǒng),講得全面的文章,導(dǎo)致我們在學習的時候,往往半知半解,學完還是一臉懵逼。
學習協(xié)程的第一門課程,是要認識生成器,有了生成器的基礎(chǔ),才能更好地理解協(xié)程。
如果你是新手,那么你應(yīng)該知道迭代器,對生成器應(yīng)該是比較陌生的吧。沒關(guān)系,看完這系列文章,你也能從小白成功過渡為Ptyhon高手。
可迭代、迭代器、生成器
初學Python的時候,對于這三貨真的是傻傻分不清。甚至還認為他們是等價的。
其實,他們是不一樣的。
可迭代的對象,很好理解,我們很熟悉的:字符串,list,dict,tuple,deque等
為了驗證我說的,需要借助collections.abc這個模塊(Python2沒有),使用isinstance來類別一個對象是否是可迭代的(Iterable),是否是迭代器(Iterator),是否是生成器(Generator)。
輸出結(jié)果
從結(jié)果來看,這些可迭代對象都不是迭代器,也不是生成器。它們有一個共同點,就是它們都可以使用for來循環(huán)。這一點,大家都知道,我們就不去驗證了。
擴展知識:
可迭代對象,是其內(nèi)部實現(xiàn)了,__iter__ 這個魔術(shù)方法。
可以通過,dir方法來查看是否有__iter__來判斷一個變量是否是可迭代的。
接下來是,迭代器。
對比可迭代對象,迭代器其實就只是多了一個函數(shù)而已。就是__next__,我們可以不再使用for循環(huán)來間斷獲取元素值。而可以直接使用next方法來實現(xiàn)。
迭代器,是在可迭代的基礎(chǔ)上實現(xiàn)的。要創(chuàng)建一個迭代器,我們首先,得有一個可迭代對象。
現(xiàn)在就來看看,如何創(chuàng)建一個可迭代對象,并以可迭代對象為基礎(chǔ)創(chuàng)建一個迭代器。
輸出
如果上面的代碼太多,也可以看這邊,你更能理解。
接下來,是我們的重點,生成器。
生成器的概念在 Python 2.2 中首次出現(xiàn),之所以引入生成器,是為了實現(xiàn)一個在計算下一個值時不需要浪費空間的結(jié)構(gòu)。
前面我們說,迭代器,是在可迭代的基礎(chǔ)上,加了一個next方法。
而生成器,則是在迭代器的基礎(chǔ)上(可以用for循環(huán),可以使用next),再實現(xiàn)了yield。
yield 是什么東西呢,它相當于我們函數(shù)里的return。在每次next,或者for遍歷的時候,都會yield這里將新的值返回回去,并在這里阻塞,等待下一次的調(diào)用。正是由于這個機制,才使用生成器在Python編程中大放異彩。實現(xiàn)節(jié)省內(nèi)存,實現(xiàn)異步編程。
如何創(chuàng)建一個生成器,主要有如下兩種方法
使用列表生成式
實現(xiàn)yield的函數(shù)
可迭代對象和迭代器,是將所有的值都生成存放在內(nèi)存中,而生成器則是需要元素才臨時生成,節(jié)省時間,節(jié)省空間。
如何運行/激活生成器
由于生成器并不是一次生成所有元素,而是一次一次的執(zhí)行返回,那么如何刺激生成器執(zhí)行(或者說激活)呢?
激活主要有兩個方法
使用next
使用generator.send(None)
分別看下例子,你就知道了。
輸出
生成器的執(zhí)行狀態(tài)
生成器在其生命周期中,會有如下四個狀態(tài)
GEN_CREATED # 等待開始執(zhí)行
GEN_RUNNING # 解釋器正在執(zhí)行(只有在多線程應(yīng)用中才能看到這個狀態(tài))
GEN_SUSPENDED # 在yield表達式處暫停
GEN_CLOSED # 執(zhí)行結(jié)束