1. 程式人生 > >python 之生成器 yield

python 之生成器 yield

一、生成器的概念綜述

一個帶有 yield 的函式就是一個 generator,它和普通函式不同,生成一個 generator 看起來像函式呼叫,但不會執行任何函式程式碼,直到對其呼叫 next()(在 for 迴圈中會自動呼叫 next())才開始執行。雖然執行流程仍按函式的流程執行,但每執行到一個 yield 語句就會中斷,並返回一個迭代值,下次執行時從 yield 的下一個語句繼續執行。看起來就好像一個函式在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的迭代值。

yield 的好處是顯而易見的,把一個函式改寫為一個 generator 就獲得了迭代能力,比起用類的例項儲存狀態來計算下一個 next() 的值,不僅程式碼簡潔,而且執行流程異常清晰。

廖雪峰大神寫的yield的文章

https://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/

二、經典案例,生產者消費者模型

瞭解該模型,需要知道兩個函式的呼叫過程,通過debug模式逐步執行:

1.

consumer.send(None)    data = yield     producer = produce(consumer)  進入for迴圈三句話;
執行produce列印語句;   consumer.send(data)  data = yield(第二次到達,此時yield帶來了data的資料並賦值給data變數)
執行consume列印語句;   data = yield(第三次到達)  yield   進入for迴圈三句話;
yield   執行 print('現在執行yield之後的函式') 這句話。
執行produce列印語句;開始迴圈。
由此可知:每個函式在被呼叫過程中,到達yield關鍵詞後,立馬在yield這地方停止,並跳出該函式,進行繼續進行其它程式碼的執行;當該函式再次被呼叫時候,從yield停止的地方開始執行函式後面的程式碼。

 

import random


def get_data():
    """返回0到9之間的3個隨機數"""
    return random.sample(range(10), 3)


def consume():
    """顯示每次傳入的整數列表的動態平均值"""
    running_sum = 0
    data_items_seen = 0

    while True:
        data = yield
        data_items_seen += len(data)
        running_sum += sum(data)
        print('The running average is {}'.format(running_sum / float(data_items_seen)))


def produce(consumer):
    """產生序列集合,傳遞給消費函式(consumer)"""
    while True:
        data = get_data()
        print('Produced {}'.format(data))
        consumer.send(data)
        yield


if __name__ == '__main__':
    consumer = consume()
    consumer.send(None)
    producer = produce(consumer)

    for _ in range(10):
        print('Producing...')
        next(producer)