python yield from用法

姓名:曾國強

學號:19021210984

轉載自https://blog.csdn.net/qq_27825451/article/details/85244237

【嵌牛導讀】

【嵌牛正文】

一濒翻、yield from 的簡單實現

我們了解到胖缤,yield是每次“惰性返回”一個值颜屠,其實從名字中就能看出,yield from 是yield的升級改進版本堡称,如果將yield理解成“返回”,那么yield from就是“從什么(生成器)里面返回”臭笆,這就構成了yield from的一般語法脉执,即

yield from generator

這樣的形式。我們通過一個簡單例子來看:

def generator2():

????yield 'a'? ?

????yield 'b'? ?

????yield 'c'? ?

????yield from [11,22,33,44]? ?

????yield from (12,23,34)? ?

????yield from range(3)?

for i in generator2():? ?

????print(i,end=' , ')

'''運行的結果為:

a , b , c? , 11 , 22 , 33 , 44 , 12 , 23 , 34 , 0 , 1 , 2 ,

'''

總結:

從上面的代碼可以看書盲憎,yield from 后面可以跟的可以是“ 生成器 嗅骄、元組胳挎、 列表饼疙、range()函數產生的序列等可迭代對象”

簡單地說,yield from? generator 慕爬。實際上就是返回另外一個生成器窑眯。而yield只是返回一個元素。從這個層面來說医窿,有下面的等價關系:yield from iterable本質上等于 for item in iterable: yield item 磅甩。

二、yield from的高級應用

1姥卢、針對yield無法獲取生成器return的返回值

我們都知道卷要,在使用yield生成器的時候,如果使用for語句去迭代生成器独榴,則不會顯式的出發(fā)StopIteration異常僧叉,而是自動捕獲StopIteration異常,所以如果遇到return棺榔,只是會終止迭代瓶堕,而不會觸發(fā)異常,故而也就沒辦法獲取return的值症歇。如下:

def my_generator():

????for i in range(5):? ? ? ?

????????if i==2:? ? ? ? ? ?

????????????return '我被迫中斷了'? ? ? ?

????????else:? ? ? ? ? ?

????????????yield i

def main(generator):? ?

????try:? ? ?

????????for i in generator:

????????????print(i)? ?

????except StopIteration as exc:? ? ? ?

????????print(exc.value)

g=my_generator()

main(g)

'''運行結果為:0 1'''

從上面的例子可以看出郎笆,for迭代語句不會顯式觸發(fā)異常,故而無法獲取到return的值忘晤,迭代到2的時候遇到return語句宛蚓,隱式的觸發(fā)了StopIteration異常,就終止迭代了设塔,但是在程序中不會顯示出來苍息。

def my_generator():

????for i in range(5):? ? ? ?

????????if i==2:? ? ? ? ? ?

????????????return '我被迫中斷了'? ? ? ?

????????else:? ? ? ? ? ?

????????????yield i

def wrap_my_generator(generator):

????result=yield from generator? ? ?

????print(result)

def main(generator):? ?

????for j in generator:? ? ? ?

????????print(j)

g=my_generator()

wrap_g=wrap_my_generator(g)

main(wrap_g)?

'''運行結果為:0 1 我被迫中斷了'''

從上面的比較可以看出,yield from具有以下幾個特點:

(1)上面的my_generator是原始的生成器,main是調用方竞思,使用yield的時候表谊,只涉及到這兩個函數,即“調用方”與“生成器(協程函數)”是直接進行交互的盖喷,不涉及其他方法爆办,即“調用方——>生成器函數(協程函數)”;

(2)在使用yield from的時候课梳,多了一個對原始my_generator的包裝函數距辆,然后調用方是通過這個包裝函數(后面會講到它專有的名詞)來與生成器進行交互的,即“調用方——>生成器包裝函數——>生成器函數(協程函數)”暮刃;

(3)yield from iteration結構會在內部自動捕獲 iteration生成器的StopIteration 異常跨算。這種處理方式與 for 循環(huán)處理 StopIteration 異常的方式一樣。而且對 yield from 結構來說椭懊,解釋器不僅會捕獲 StopIteration 異常诸蚕,還會把return返回的值或者是StopIteration的value 屬性的值變成 yield from 表達式的值,即上面的result氧猬。

2背犯、yield from所實現的數據傳輸通道

前面總結的幾個特點里面已經介紹了yield和yield from的數據交互方式,yield涉及到“調用方與生成器兩者”的交互盅抚,生成器通過next()的調用將值返回給調用者漠魏,而調用者通過send()方法向生成器發(fā)送數據;

但是yield還有一個第三者函數妄均,下面將先從相關的概念說起柱锹。

在PEP 380 使用了一些yield from使用的專門術語:

委派生成器:包含 yield from <iterable> 表達式的生成器函數;即上面的wrap_my_generator生成器函數

子生成器:從 yield from 表達式中 <iterable> 部分獲取的生成器丰包;即上面的my_generator生成器函數

調用方:調用委派生成器的客戶端代碼禁熏;即上面的main生成器函數

下圖是這三者之間的交互關系(摘自博客園):


委派生成器在 yield from 表達式處暫停時,調用方可以直接把數據發(fā)給子生成器烫沙,子生成器再把產出的值發(fā)給調用方匹层。子生成器返回之后,解釋器會拋出StopIteration 異常锌蓄,并把返回值附加到異常對象上升筏,此時委派生成器會恢復。

總結:

(1)yield from主要設計用來向子生成器委派操作任務瘸爽,但yield from可以向任意的可迭代對象委派操作您访;

(2)委派生成器(group)相當于管道,所以可以把任意數量的委派生成器連接在一起---一個委派生成器使用yield from 調用一個子生成器剪决,而那個子生成器本身也是委派生成器灵汪,使用yield from調用另一個生成器檀训。

(3)針對yield存在的第二個缺點

首先看一下他要表述的意思是什么?它的局限性在于只能向它的直接調用者每次yield一個值享言。這意味著那些包含yield的代碼不能像其他代碼那樣被分離出來放到一個單獨的函數中峻凫。這也正是yield from要解決的。具體參見上文:

https://blog.csdn.net/qq_27825451/article/details/85234610

這句話確實難以理解览露,但是他要表達的意思實際上是:因為生成器從定義上來看荧琼,就像是一個普通的函數,那么既然作為普通函數差牛,就應該可以反反復復調用都沒問題的命锄,但是生成器卻并不行。那為什么yield from可以解決這樣的問題呢偏化,主要是因為yield from后面可以跟任意一個生成器脐恩,即yield from可以將任意的任務為派給任意生成器函數,從而避免了子生成器直接向調用者返回單個值的情況侦讨。

三驶冒、yield from的用法示例

其實yield from最重要的作用就是提供了一個“數據傳輸的管道”,下面通過一個簡單的例子加以說明為什么是管道:

def average():

????total = 0

????count = 0?

????avg = None

????while True:? ? ? ?

????????num = yield avg? ? ? ?

????????total += num? ? ? ?

????????count += 1? ? ? ?

????????avg = total/count

def wrap_average(generator):? ?

????yield from generator

def main(wrap):? ?

????print(next(wrap))? ?

????print(wrap.send(10))

????print(wrap.send(20))

????print(wrap.send(30))

????print(wrap.send(40))

g = average()

wrap=wrap_average(g)

main(wrap)

'''運行結果為:None 10.0 15.0 20.0 25.0'''

從上面我們可以發(fā)現搭伤,調用方發(fā)送的數據是發(fā)給wrap_average的只怎,怎么依然到了生成器函數average里面呢袜瞬?這就是“數據傳輸管道的作用”怜俐。即主函數調用方main把各個value傳給grouper ,而這個傳入的值最終到達averager函數中邓尤; grouper并不知道傳入的是什么值拍鲤,因為從上面的代碼看出,wrap_average里面完全沒有處理這個值的任何代碼汞扎!

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末季稳,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子澈魄,更是在濱河造成了極大的恐慌景鼠,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痹扇,死亡現場離奇詭異铛漓,居然都是意外死亡,警方通過查閱死者的電腦和手機鲫构,發(fā)現死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門浓恶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人结笨,你說我怎么就攤上這事包晰∈疲” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵伐憾,是天一觀的道長勉痴。 經常有香客問我,道長树肃,這世上最難降的妖魔是什么蚀腿? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮扫外,結果婚禮上莉钙,老公的妹妹穿的比我還像新娘。我一直安慰自己筛谚,他們只是感情好磁玉,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著驾讲,像睡著了一般蚊伞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吮铭,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天时迫,我揣著相機與錄音,去河邊找鬼谓晌。 笑死掠拳,一個胖子當著我的面吹牛,可吹牛的內容都是我干的纸肉。 我是一名探鬼主播溺欧,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼柏肪!你這毒婦竟也來了姐刁?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤烦味,失蹤者是張志新(化名)和其女友劉穎聂使,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體谬俄,經...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡柏靶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了凤瘦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宿礁。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蔬芥,靈堂內的尸體忽然破棺而出梆靖,到底是詐尸還是另有隱情控汉,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布返吻,位于F島的核電站姑子,受9級特大地震影響,放射性物質發(fā)生泄漏测僵。R本人自食惡果不足惜街佑,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捍靠。 院中可真熱鬧沐旨,春花似錦、人聲如沸榨婆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽良风。三九已至谊迄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烟央,已是汗流浹背统诺。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留疑俭,地道東北人粮呢。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像怠硼,于是被迫代替她去往敵國和親鬼贱。 傳聞我的和親對象是個殘疾皇子移怯,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354