【python】生成器中 yield from 句法

yield from 句法

在生成器中使用yield from subgen()時,subgen會獲得控制權(quán)逸爵,把產(chǎn)出的值傳給生成器的調(diào)用方,即調(diào)用方可以直接控制subgen。與此同時背捌,gen會阻塞,等待subgen終止洞斯。

【簡單應(yīng)用】用來簡化for循環(huán)中的yield表達式

舉個栗子:

def gen():
    for c in 'AB':
        yield c

    for i in range(1,3):
        yield i

print(list(gen()))

前后對比

def gen():
    yield from 'AB'
    yield from range(1,3)
    
print(list(gen()))

【解釋】yield from x表達式對x對象所做的第一件事是毡庆,調(diào)用iter(x),從中獲取迭代器烙如。因此么抗,x可以是任何可迭代的對象。


【應(yīng)用升級】把職責(zé)委托給子生成器

yield from 的主要功能是打開雙向通道亚铁,把最外層的調(diào)用方與最內(nèi)層的子生成器連接起來蝇刀,這樣二者可以直接發(fā)送和產(chǎn)出值,還可以直接傳入異常刀闷,而不用在位于中間的協(xié)程中添加大量處理異常的樣板代碼熊泵。通過這個結(jié)構(gòu),協(xié)程可以把功能委托給子生成器甸昏。

主要術(shù)語:

  • 委派生成器:
    包含 yield from <iterable> 表達式的生成器函數(shù)顽分。

  • 子生成器:
    從 yield from 表達式中 <iterable>部分獲取的生成器函數(shù)。

  • 調(diào)用方
    調(diào)用委派生成器的客戶端(調(diào)用方)代碼施蜜。

graph LR
調(diào)用方 ==> 委派生成器
委派生成器 ==> 子生成器

【店小二】:各位看官卒蘸,下面的代碼請查收@ @

from collections import namedtuple

Result = namedtuple('Result','count average')

# 子生成器
def averager():
    total = 0.0
    count = 0
    average = None

    while True:
        # main 方法中發(fā)送的各種值,會綁定到term變量上
        term = yield
        
        # 子生成器終止的條件
        if term is None:
            break

        total += term
        count += 1
        average = total / count
    
    # 返回值會成為grouper中 yield from表達式的值
    return Result(count,average)

# 委派生成器
def grouper(results,key):
    while True:
        # 每次迭代都會生成一個averager實例翻默。每個生成器都是本協(xié)程(grouper)使用的生成器對象缸沃。
        results[key] = yield from averager()

# 客戶端代碼
def main(data):
    results = {}
    for key,values in data.items():
        # results 用來存儲結(jié)果
        group = grouper(results, key)
        # 預(yù)激活協(xié)程
        next(group)
        for value in values:
            # 發(fā)送的每個值都會經(jīng)由grouper的yield from處理,通過管道傳給averager實例修械。同時趾牧,當(dāng)前的grouper實例,會在yield from 處暫停肯污。
            group.send(value)
        # 把None值傳入grouper翘单,導(dǎo)致當(dāng)前的averager實例終止吨枉,并讓grouper繼續(xù)運行,再創(chuàng)建一個aveager實例哄芜,處理下一組值貌亭。
        group.send(None)
    print(results)

data = {
    'girls;kg':[40.9,38.5,44.3,42.2,45.2,41.7,44.5,38.0,40.6,44.5],
    'girls;m':[1.6,1.51,1.4,1.3,1.41,1.39,1.33,1.46,1.45,1.43],
    'boys;kg':[39.0,40.8,43.2,40.8,43.1,38.6,41.4,40.6,36.3],
    'boys;m':[1.38,1.5,1.32,1.25,1.37,1.48,1.25,1.49,1.46]
}


main(data)

Output:

{'girls;kg': Result(count=10, average=42.040000000000006), 'girls;m': Result(count=10, average=1.4279999999999997), 'boys;kg': Result(count=9, average=40.422222222222224), 'boys;m': Result(count=9, average=1.3888888888888888)}

【提示】委派生成器在yield from 表達式處暫停時,調(diào)用方可以直接把數(shù)據(jù)發(fā)給子生成器认臊,子生成器再把產(chǎn)出的值發(fā)給調(diào)用方圃庭。子生成器返回之后,解釋器會拋出StopIteration異常失晴,并把返回值附加到異常對象上剧腻,此時委派生成器會恢復(fù)運行。


【重點】

yield from 句法的注意點
  • 如果子生成器不終止师坎,委派生成器會在yield from處永遠(yuǎn)暫停恕酸。

  • 因為委派生成器相當(dāng)于管道,所以可以把任意數(shù)量個委派生成器連接在一起:一個委派生成器使用yield from調(diào)用一個子生成器胯陋,而那個子生成器本身也是委派生成器蕊温,使用yield from調(diào)用另一個子生成器,以此類推遏乔。最終义矛,這個鏈條要以一個只使用yield表達式的簡單生成器結(jié)束碳柱;不過巡蘸,也能以任何可迭代的對象結(jié)束幌缝。

  • 任何yield from鏈條都必須由客戶驅(qū)動练俐,在最外層委派生成器上調(diào)用next(...)函數(shù)或.send(...)方法。

yield from 句法的意義

【寫在前面】下面的幾點知識...有點復(fù)雜盒揉,考慮的如果不夠全面的話灯谣,可能寫的程序會崩均澳。

  • 子生成器產(chǎn)出的值都直接傳給委派生成器的調(diào)用方(即客戶端代碼)胞谭。

  • 使用send()方法發(fā)給委派生成器的值都直接傳給子生成器垃杖。如果發(fā)送的值是None,那么會調(diào)用子生成器的next()方法丈屹。

如果發(fā)送的值不是None调俘,那么會調(diào)用子生成器的send()方法。如果調(diào)用的方法拋出StopIteration異常旺垒,那么委派生成器恢復(fù)運行彩库。任何其他異常都會向上冒泡,傳給委派生成器先蒋。

  • 生成器退出時骇钦,生成器(或子生成器)中的return expr表達式會觸發(fā)StopIteration(expr)異常拋出。

  • yield from表達式的值是子生成器終止時傳給StopIteration異常的第一個參數(shù)竞漾。

  • 傳入委派生成器的異常司忱,除了GeneratorExit之外都傳給子生成器的throw()方法皇忿。

如果調(diào)用throw()方法時拋出StopIteration異常,委派生成器恢復(fù)運行坦仍。StopIteration之外的異常會向上冒泡,傳給委派生成器叨襟。

  • 如果把GeneratorExit異常傳入委派生成器繁扎,或者在委派生成器上調(diào)用close()方法,那么在子生成器上調(diào)用close()方法糊闽,如果它有的話梳玫。如果調(diào)用close()方法導(dǎo)致異常拋出,那么異常會向上冒泡右犹,傳給委派生成器提澎;否則,委派生成器拋出GeneratorExit異常念链。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盼忌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子掂墓,更是在濱河造成了極大的恐慌谦纱,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件君编,死亡現(xiàn)場離奇詭異跨嘉,居然都是意外死亡,警方通過查閱死者的電腦和手機吃嘿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門祠乃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人兑燥,你說我怎么就攤上這事亮瓷。” “怎么了贪嫂?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵寺庄,是天一觀的道長。 經(jīng)常有香客問我力崇,道長斗塘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任亮靴,我火速辦了婚禮馍盟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茧吊。我一直安慰自己贞岭,他們只是感情好八毯,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瞄桨,像睡著了一般话速。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上芯侥,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天泊交,我揣著相機與錄音,去河邊找鬼柱查。 笑死廓俭,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的唉工。 我是一名探鬼主播研乒,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼淋硝!你這毒婦竟也來了雹熬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤奖地,失蹤者是張志新(化名)和其女友劉穎橄唬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體参歹,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡仰楚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了犬庇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片僧界。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖臭挽,靈堂內(nèi)的尸體忽然破棺而出捂襟,到底是詐尸還是另有隱情,我是刑警寧澤欢峰,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布葬荷,位于F島的核電站,受9級特大地震影響纽帖,放射性物質(zhì)發(fā)生泄漏宠漩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一懊直、第九天 我趴在偏房一處隱蔽的房頂上張望扒吁。 院中可真熱鬧,春花似錦室囊、人聲如沸雕崩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盼铁。三九已至粗蔚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捉貌,已是汗流浹背支鸡。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留趁窃,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓急前,卻偏偏與公主長得像醒陆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子裆针,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

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