1.Generator Expressionshtml
生成器表達式是用小括號表示的簡單生成器標記法:python
generator_expression ::= "(" expression comp_for ")"express
生成器表達式產生一個生成器對象,它的語法和for相似,出了它是被「()」包含,而不是[]或{};app
生成器表達式中變量的計算被延遲到__next__()函數的調用,然而最左邊for循環子句被當即計算,這樣,若是他有錯誤的話能夠被當即看到。後面的for循環子句不能被當即計算,由於他們可能依賴於前面的for循環,例如(x*y for x in range(10) for y in bar(x))異步
python3.6之後,若是生成器出如今async def function中,那麼async for子句和await表達式能夠被理解爲是異步的。若是生成器表達式包含async for子句或者await表達式,就叫作異步生成器表達式。異步生成器表達式產生一個新的異步生成器對象,它是一個異步迭代器。async
2. Yield Expressions函數
yield_atom ::= "(" ")" yield_expression ::= "yield" [ | "from" ]
Yield表達式用於定義一個生成器函數或異步生成器函數,所以只能被用於一個函數定義體內。在一個函數定義體中使用yield表達式使其成爲生成器,
在一個async def函數體內使用yield表達式使協程函數成爲一個異步生成器。例如:
def gen(): //定義一個生成器函數
yield 123
async def agen(): //定義一個異步生成器函數
yield 123
當一個生成器函數被調用,它返回一個迭代器,也叫生成器。這個生成器控制生成器函數的執行。當生成器的一個函數被調用的時候,生成器函數開始執行。
執行到第一個yield表達式時,掛起,返回expression_list的值給調用者。對於掛起,咱們指的是全部局部狀態被保留,包含當前局部變量的綁定,
指令指針,內部調用棧,任何異常處理狀態。當經過調用生成器的一個函數恢復執行時,函數的執行就好像是從外部再次調用yield表達式同樣。恢復執行後,
yield表達式的值取決調用的方法。若是是__next__()被調用(通常經過for循環或者內置的next()函數),那麼值是None。若是是send()被調用,
值是傳給send的參數的值。
全部的這些使得生成器函數很是像協程;它產生屢次值,有多個入口點而且執行能夠被掛起。惟一的不一樣是,生成器函數yield後不能控制程序從哪裏繼續執行,
控制權老是傳回給生成器的調用者。
yield表達式能夠在try塊的任何地方,若是生成器在被結束(到達零引用或者由於垃圾回收機制)以前沒有被恢復執行,生成器的close函數被調用,所以finally
子句被執行。
當yield from <expr> 被使用,它把附加的表達式當成一個子迭代器,全部子迭代器產生的值被直接傳回給當前生成器函數的調用者。當前生成器調用send的參數值
和調用throw的異常參數 都將被傳給底層迭代器(子迭代器),若是他有對應的方法的話。不然,send致使AttributeError或者TypeError,而throw當即
raise傳給他的異常。
當底層迭代器執行完成,StopIteration對象的value值變成這個yield from表達式的值。這個值能夠被顯式的設置當產生StopIteration時,或者自動設置,若是
子迭代器是一個生成器(子生成器返回一個值)yield_expressionexpression_listexpression
3. 生成器-迭代器 方法
這部分介紹生成器迭代器的方法,他們能夠被用來控制生成器函數的執行。當生成器正在執行時調用這些函數將致使ValueError。
(1)generator.__next__()
開始生成器函數的執行或者從最後被執行的yield表達式中恢復執行,若是是恢復執行,yield表達式的值是None,繼續執行到下一個yield表達式,
掛起,返回expression_list的值給__next__()的調用者。若是生成器沒有再yield一個值,則產生一個StopIteration異常
這個方法通常被隱式調用,例如for循環,next()
(2)generator.send(value)
恢復執行而且發送一個值到生成器函數。這個value參數就是當前yield表達式的結果。send方法返回下一個生成器yield的值
若是沒有yield,返回StopIteration。當用send來啓動生成器,他的參數必須是None,由於沒有yield表達式接收值。
(3)generator.throw(type[,value[,traceback]])
在生成器掛起的地方產生一個type類型的異常,而且返回下一個生成器函數yield的值,若是沒有yield,返回StopIteration。
若是生成器函數沒有捕獲這個傳進去的異常 ,或者產生了另外一個不一樣的異常,那麼將這個異常傳遞給調用者。
(4)generator.close()
在生成器掛起的地方產生一個GeneratorExit(),若是生成器以後優雅的退出,已經關閉,或者產生了一個GeneartorExit(不捕獲該異常),close將返回到它的
調用者。若是生成器yield一個值,那麼產生一個RuntimeError。若是生成器產生了任何其餘異常,將傳遞給調用者。若是
生成器由於一個異常或者正常退出,那麼close不作任何事情。
實例:
>>> def echo(value=None): ... print("Execution starts when 'next()' is called for the first time.") ... try: ... while True: ... try: ... value = (yield value) ... except Exception as e: ... value = e ... finally: ... print("Don't forget to clean up when 'close()' is called.") ... >>> generator = echo(1) >>> print(next(generator)) Execution starts when 'next()' is called for the first time. 1 >>> print(next(generator)) None >>> print(generator.send(2)) 2 >>> generator.throw(TypeError, "spam") TypeError('spam',) >>> generator.close() Don't forget to clean up when 'close()' is called.
PEP380 加入了yield from表達式,容許一個生成器委派部分操做給另外一個生成器。這能夠剔除一部分包含yield的代碼放到另外一個生成器。另外,
子生成器能夠返回一個值,這個值對於委託生成器也是可用的。
雖然主要涉及用來委派一個子生成器,可是yield from 表達式事實上能夠委派任何的子迭代器。
低於簡單的迭代器, yield from iterable 本質上就是一個簡短的形式:for item in iterable: yield item,例如:
>>> def g(x): ... yield from range(x, 0, -1) ... yield from range(x) ... >>> list(g(5)) [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
然而,不像普通的循環,yield from 容許子生成器直接從調用區域接收send和throw的值,而且返回一個最後的值給外層生成器。示例以下:
>>> def accumulate(): ... tally = 0 ... while 1: ... next = yield ... if next is None: ... return tally ... tally += next ... >>> def gather_tallies(tallies): ... while 1: ... tally = yield from accumulate() ... tallies.append(tally) ... >>> tallies = [] >>> acc = gather_tallies(tallies) >>> next(acc) # Ensure the accumulator is ready to accept values >>> for i in range(4): ... acc.send(i) ... >>> acc.send(None) # Finish the first tally >>> for i in range(5): ... acc.send(i) ... >>> acc.send(None) # Finish the second tally >>> tallies [6, 10]