徹底理解Python中的yield

閱讀別人的python源碼時(shí)碰到了這個(gè)yield這個(gè)關(guān)鍵字,各種搜索終于搞懂了,在此做一下總結(jié):

  1. 通常的for...in...循環(huán)中,in后面是一個(gè)數(shù)組,這個(gè)數(shù)組就是一個(gè)可迭代對(duì)象,類似的還有鏈表,字符串,文件。它可以是mylist = [1, 2, 3],也可以是mylist = [x*x for x in range(3)]。
    它的缺陷是所有數(shù)據(jù)都在內(nèi)存中,如果有海量數(shù)據(jù)的話將會(huì)非常耗內(nèi)存。
  2. 生成器是可以迭代的,但只可以讀取它一次。因?yàn)橛玫臅r(shí)候才生成。比如 mygenerator = (x*x for x in range(3)),注意這里用到了(),它就不是數(shù)組,而上面的例子是[]。
  3. 我理解的生成器(generator)能夠迭代的關(guān)鍵是它有一個(gè)next()方法,工作原理就是通過(guò)重復(fù)調(diào)用next()方法,直到捕獲一個(gè)異常。可以用上面的mygenerator測(cè)試。
  4. 帶有 yield 的函數(shù)不再是一個(gè)普通函數(shù),而是一個(gè)生成器generator,可用于迭代,工作原理同上。
  5. yield 是一個(gè)類似 return 的關(guān)鍵字,迭代一次遇到y(tǒng)ield時(shí)就返回yield后面(右邊)的值。重點(diǎn)是:下一次迭代時(shí),從上一次迭代遇到的yield后面的代碼(下一行)開(kāi)始執(zhí)行。
  6. 簡(jiǎn)要理解:yield就是 return 返回一個(gè)值,并且記住這個(gè)返回的位置,下次迭代就從這個(gè)位置后(下一行)開(kāi)始。
  7. 帶有yield的函數(shù)不僅僅只用于for循環(huán)中,而且可用于某個(gè)函數(shù)的參數(shù),只要這個(gè)函數(shù)的參數(shù)允許迭代參數(shù)。比如array.extend函數(shù),它的原型是array.extend(iterable)。
  8. send(msg)與next()的區(qū)別在于send可以傳遞參數(shù)給yield表達(dá)式,這時(shí)傳遞的參數(shù)會(huì)作為yield表達(dá)式的值,而yield的參數(shù)是返回給調(diào)用者的值。——換句話說(shuō),就是send可以強(qiáng)行修改上一個(gè)yield表達(dá)式值。比如函數(shù)中有一個(gè)yield賦值,a = yield 5,第一次迭代到這里會(huì)返回5,a還沒(méi)有賦值。第二次迭代時(shí),使用.send(10),那么,就是強(qiáng)行修改yield 5表達(dá)式的值為10,本來(lái)是5的,那么a=10
  9. send(msg)與next()都有返回值,它們的返回值是當(dāng)前迭代遇到y(tǒng)ield時(shí),yield后面表達(dá)式的值,其實(shí)就是當(dāng)前迭代中yield后面的參數(shù)。
  10. 第一次調(diào)用時(shí)必須先next()或send(None),否則會(huì)報(bào)錯(cuò),send后之所以為None是因?yàn)檫@時(shí)候沒(méi)有上一個(gè)yield(根據(jù)第8條)。可以認(rèn)為,next()等同于send(None)。

代碼示例1:

#encoding:UTF-8  
def yield_test(n):  
    for i in range(n):  
        yield call(i)  
        print("i=",i)  
    #做一些其它的事情      
    print("do something.")      
    print("end.")  
  
def call(i):  
    return i*2  
  
#使用for循環(huán)  
for i in yield_test(5):  
    print(i,",")  

結(jié)果是:

>>>   
0 ,  
i= 0  
2 ,  
i= 1  
4 ,  
i= 2  
6 ,  
i= 3  
8 ,  
i= 4  
do something.  
end.  
>>> 

理解的關(guān)鍵在于:下次迭代時(shí),代碼從yield的下一跳語(yǔ)句開(kāi)始執(zhí)行。

代碼示例2:

def node._get_child_candidates(self, distance, min_dist, max_dist):
    if self._leftchild and distance - max_dist < self._median:
        yield self._leftchild
    if self._rightchild and distance + max_dist >= self._median:
        yield self._rightchild

與前面不同的是,這個(gè)函數(shù)中沒(méi)有for循環(huán),但它依然可以用于迭代。
node._get_child_candidates函數(shù)中有yield,所以它變成了一個(gè)迭代器,可以用于迭代。
執(zhí)行第一次迭代時(shí)(其實(shí)就是調(diào)用next()方法),如果有左節(jié)點(diǎn)并且距離滿足要求,會(huì)執(zhí)行第一個(gè)yield,這時(shí)會(huì)返回self._leftchild并完成第一個(gè)迭代。
執(zhí)行第二次迭代時(shí),從第一個(gè)yield后面開(kāi)始,如果有右節(jié)點(diǎn)并且距離滿足要求,會(huì)執(zhí)行第二個(gè)yield,這時(shí)會(huì)返回self._rightchild并完成第一個(gè)迭代。
執(zhí)行第三次迭代時(shí),第二個(gè)yield后再無(wú)代碼,捕獲異常,退出迭代。

調(diào)用過(guò)程:

result, candidates = list(), [self]
while candidates:
    node = candidates.pop()
    distance = node._get_dist(obj)
    if distance <= max_dist and distance >= min_dist:
        result.extend(node._values)
    candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result

上面的node._get_child_candidates(self, distance, min_dist, max_dist)是放在extend()函數(shù)中作為參數(shù)的,為什么可以這么用,就因?yàn)閑xtend函數(shù)的參數(shù)不僅僅支持array,只要它是一個(gè)迭代器就可以。它的原型是array.extend(iterable)。

代碼示例3:

參考文章

上面的筆記離不開(kāi)下面文章的幫助,尤其是第一篇:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 第五章 序列和協(xié)程 來(lái)源:Chapter 5: Sequences and Coroutines 譯者:飛龍 協(xié)議...
    布客飛龍閱讀 665評(píng)論 0 37
  • Python 是一種相當(dāng)高級(jí)的語(yǔ)言,通過(guò) Python 解釋器把符合語(yǔ)法的程序代碼轉(zhuǎn)換成 CPU 能夠執(zhí)行的機(jī)器碼...
    Python程序媛閱讀 1,941評(píng)論 0 3
  • 本文翻譯自Functional Programming Howto 本文將介紹Python中函數(shù)式編程的特性。在對(duì)...
    大蟒傳奇閱讀 2,638評(píng)論 4 14
  • 個(gè)人筆記,方便自己查閱使用 Py.LangSpec.Contents Refs Built-in Closure ...
    freenik閱讀 67,743評(píng)論 0 5
  • 01 六月初的晚上,媽媽安靜睡在沙發(fā)上,爸爸懷著躲閃的目光。 酷暑又心亂,九號(hào)以后,大家都來(lái)了,房間里人滿為患,我...
    舊迷樓閱讀 386評(píng)論 0 1