1. 程式人生 > >yield 與 yield from

yield 與 yield from

簡而言之yield from 就是把main裡的send資料 傳入yield處,  send(None)的功能近乎於next(w)

def test1():
      while True:   
            yield from test2()

def test2():
      while True:
            y = yield 
            if y == None:
                break

def main():
      w = test1()
      next(w)  
      
for i in range(0, 10): w.send(i) w.send(None)
main()

 

 

 

三者之間的關係圖

 

 

委派生成器在 yield from 表示式處暫停時,呼叫方可以直接把資料發給子生成器,子生成器再把產出的值發給呼叫方。子生成器返回之後,直譯器會丟擲StopIteration 異常,並把返回值附加到異常物件上,此時委派生成器會恢復。

 

 

grouper 傳送的每個值都會經由 yield from 處理,通過管道傳給 averager 例項。grouper 會在 yield from 表示式處暫停,等待 averager 例項處理客戶端發來的值。averager 例項執行完畢後,返回的值繫結到 results[key] 上。while 迴圈會不斷建立 averager 例項,處理更多的值。

外層 for 迴圈重新迭代時會新建一個 grouper 例項,然後繫結到 group 變數上。前一個 grouper 例項(以及它建立的尚未終止的 averager 子生成器例項)被垃圾回收程式回收。

from collections import namedtuple

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

# 子生成器
def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        # main 函式傳送資料到這裡 
print("in averager, before yield") term = yield if term is None: # 終止條件 break total += term count += 1 average = total/count print("in averager, return result") return Result(count, average) # 返回的Result 會成為grouper函式中yield from表示式的值 # 委派生成器 def grouper(results, key): # 這個迴圈每次都會新建一個averager 例項,每個例項都是作為協程使用的生成器物件 while True: print("in grouper, before yield from averager, key is ", key) results[key] = yield from averager() print("in grouper, after yield from, key is ", key) # 呼叫方 def main(data): results = {} for key, values in data.items(): # group 是呼叫grouper函式得到的生成器物件 group = grouper(results, key) print("\ncreate group: ", group) next(group) #預激 group 協程。 print("pre active group ok") for value in values: # 把各個value傳給grouper 傳入的值最終到達averager函式中; # grouper並不知道傳入的是什麼,同時grouper例項在yield from處暫停 print("send to %r value %f now"%(group, value)) group.send(value) # 把None傳入groupper,傳入的值最終到達averager函式中,導致當前例項終止。然後繼續建立下一個例項。 # 如果沒有group.send(None),那麼averager子生成器永遠不會終止,委派生成器也永遠不會在此啟用,也就不會為result[key]賦值 print("send to %r none"%group) group.send(None) print("report result: ") report(results) # 輸出報告 def report(results): for key, result in sorted(results.items()): group, unit = key.split(';') print('{:2} {:5} averaging {:.2f}{}'.format(result.count, group, result.average, unit)) data = { 'girls;kg':[40, 41, 42, 43, 44, 54], 'girls;m': [1.5, 1.6, 1.8, 1.5, 1.45, 1.6], 'boys;kg':[50, 51, 62, 53, 54, 54], 'boys;m': [1.6, 1.8, 1.8, 1.7, 1.55, 1.6], } if __name__ == '__main__': main(data)