背景介紹
最近在學習Tornado的async編程技巧, 發現yield是基礎, 爲了彌補以前對他的疏忽, 特此發文深刻加深其印象, 以及提升其做用。python
基礎概念
yield的做用就是掛起程序, 而且返回yield以後的值。 舉個很簡單的例子:express
#-*- coding: utf-8 -*- def gen(): b = yield "yield value" print "StateA ", b generator = gen() print generator.next()
對上述程序進行簡單的分析:編程
- 執行輸出的結果:yield value,
- generator = gen() , 建立一個生成器, (含有yield的函數體, 其函數調用的結果就是生成一個生成器, 不會執行其函數體。)
- generator.next(), 只有當生成器的next函數被第一次觸發, 函數體纔會被執行, 到第一個yield處掛起。程序稍做修改來驗證一下:
#-*- coding: utf-8 -*- def gen(): print "enter gen()" b = (yield "yield value")#pause print "StateA ", b generator = gen() print "created a generator" print generator.next()
執行結果:async
created a generator
enter gen()
yield value函數
- 若是生成器的next函數被第二次觸發(再次例子中), 因爲沒有yield了, 會在函數體執行結束以後拋出異常。
#-*- coding: utf-8 -*- def gen(): b = (yield "yield value")#pause print "StateA ", b generator = gen() print generator.next() print generator.next()
執行結果:學習
yield value
StateA None
Traceback (most recent call last):
File "yield-sample.py", line 9, in <module>
print generator.next()
StopIterationspa
- b = (yield "yield value") , 從上述的執行結果中看, b的值爲None, 同時應該注意到, 複製動做是在第二次next的時候被調用到的。
- 咱們再想, 如何讓yield expression有返回值, 而且此返回值是從外圍穿入進去的, 這正是generator.send(value)要作的事情:
#-*- coding: utf-8 -*- def gen(): b = (yield "yield value")#pause print "StateA ", b generator = gen() print generator.next() print generator.send("yield expression return value")
執行結果code
yield value
StateA yield expression return value
Traceback (most recent call last):
File "yield-sample.py", line 9, in <module>
print generator.send("yield expression return value")
StopIterationutf-8
-
下面的代碼是否是也是能夠的?generator
#-*- coding: utf-8 -*- def gen(): b = (yield "yield value")#pause print "StateA ", b generator = gen() print generator.send("yield expression return value")
其實沒啥, 就是去掉了 print generator.send(None)
執行結果
Traceback (most recent call last):
File "yield-sample.py", line 8, in <module>
print generator.send("yield expression return value")
TypeError: can't send non-None value to a just-started generator
這是爲何? 這要追述一下generator.send(value)的做用: 給yield表達式傳值, 也就是說讓(yield expression) = value, (注意: 是剛剛掛起的yield); 爲了達到這個目的, 在此以前必定要讓generator掛起一次才行, 因此在此以前必須有generator.next()/send(None) 的調用。
總結
帶有yield表達式的函數在運行的時候就是一個generator(生成器), 今生成器有兩個對外的函數, next()和send(value)
- 相同點
generator.send(None) 和generator.next() 做用是相同的。 都是驅使生成器從一個yield向下一個yield去執行函數體, 而後掛起返回yield後面的表達式。
- 不一樣點
1. generator.send(value) 要在generator.next()/send(None)以後執行, 他的做用: 返回當前掛起yield expression = value, 若是讓當前的yield掛起, 必須執行一次next()/send(None)。
2. 其實最大的不一樣就是, send能夠把函數外的value能傳到到函數中, 而next不能。