帶有yield的函式,就是一個生成器,yield與return類似,都會返回一個引數,但是最大的不同點是return值後就不會再執行程式,但是yield會在下次呼叫生成器是接著執行
def foo():print("starting...")while True:res = yield 4print("res:",res)g = foo()print(next(g))print("*"*20)print(next(g))輸出:
starting...4********************res: None4程式碼的執行順序:
1、因foo()函式中有yield關鍵字,所以foo()函式並不會真的執行,而是先得到一個生成器g物件
2、直到呼叫next()方法後,foo()函式開始執行,先執行foo()函式中print方法,進入while迴圈
3、程式遇到yield關鍵字,然後把yield想象成return,return一個4後,程式暫時停止,並未給res賦值,此時next(g)語句執行完成,所以輸出的前兩行(第一個是while上面的print的結果,第二個是return的結果)是執行print(next(g))的結果
4、程式執行print("*"*20),輸出20個*
5、執行下面的print(next(g)),這個時候和上面那個差不多,不過不同的是,這個時候是從剛才那個next程式停止的地方開始執行的,也就是要執行res的賦值操作,這時候要注意,這個時候賦值操作的右邊是沒有值的(因為剛才那個是return出去了,並沒有給賦值操作的左邊傳引數),所以這個時候res賦值是None,所以接著下面的輸出就是res:None
6、繼續在while裡執行,又一次碰到yield,這個時候同樣return 出4,然後程式停止,print函式輸出的4就是這次return出的4
yield生成器的特點:
yield 是一個類似 return的關鍵字,迭代一次遇到yield時就返回yield後面的值。重點是:下一次迭代時,從上一次迭代遇到的yield後面的程式碼開始執行帶有 yield 的函式不再是一個普通函式,而是一個生成器generator,可用於迭代生成器是可以迭代的,但只可以讀取它一次。因為用的時候才生成yield就是 return 返回一個值,並且記住這個返回的位置,下次迭代就從這個位置後開始一個生成器只能只能用一次:將一個生成器中的值全部取出來之後,再從中取值得到的是空在生成器表示式外有for迴圈時,把for迴圈拆開來分析send(msg)與next()的區別在於send可以傳遞引數給yield表示式,這時傳遞的引數會作為yield表示式的值,而yield的引數是返回給呼叫者的值。——換句話說,就是send可以強行修改上一個yield表示式值。比如函式中有一個yield賦值,a = yield 5,第一次迭代到這裡會返回5,a還沒有賦值。第二次迭代時,使用.send(10),那麼,就是強行修改yield 5表示式的值為10,本來是5的,那麼a=10def demo():for i in range(4):yield ig=demo()g1=(i for i in g)g2=(i for i in g1)print(list(g1))print(list(g2))1、在執行list(g1)之前,生成器函式,生成器表示式中的內容都沒有執行。(只有從生成器中取值時,生成器函式,生成器表示式中的內容才會執行)
2、當執行list(g1)時,就是從g1這個生成器中取值(資料型別強轉),g1又去找g要值,所以執行結果是:[0,1,2,3]
3、當執行list(g2)時,g2生成器會找g1生成器要值,而list(g1)語句,以及將生成器g1中的值取出來,所以g1是空,執行結果為:[]
def add(n,i):return n+idef test():for i in range(4):yield ig=test()for n in [1,10]:g=(add(n,i) for i in g)print(list(g))同上:在list(g)之前,生成器函式,生成器表示式內的語句都沒有執行。只有當取生成器中的值得時候才執行。
遇見for迴圈裡面有生成器表示式,將for迴圈拆解開來
n = 1 g = (add(n,i) for i in g) n = 10 g = (add(n,i) for i in g)當執行list(g)時,生成器函式或者是生成器表示式中的內容開始執行。
n就變成了迴圈中的最後一個值。
for迴圈中就變為:
n = 10
g = (add(n,i) for i in (add(n,i) for i in test()))
結果為:[20,21,22,23]