Python: generator, yield, yield from 详解
生活随笔
收集整理的這篇文章主要介紹了
Python: generator, yield, yield from 详解
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.Generator Expressions
生成器表達式是用小括號表示的簡單生成器標記法:
generator_expression ::= "(" expression comp_for ")"
生成器表達式產生一個生成器對象,它的語法和for類似,出了它是被“()”包含,而不是[]或{};
生成器表達式中變量的計算被延遲到__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表達式,就叫做異步生成器表達式。異步生成器表達式產生一個新的異步生成器對象,它是一個異步迭代器。
?
2. Yield Expressions
yield_atom ::= "(" yield_expression ")" yield_expression ::= "yield" [expression_list | "from" expression]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時,或者自動設置,如果
子迭代器是一個生成器(子生成器返回一個值) 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] ?
?
轉載于:https://www.cnblogs.com/programmer-wfq/p/7173580.html
總結
以上是生活随笔為你收集整理的Python: generator, yield, yield from 详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 树状多层级菜单展示
- 下一篇: Windows下为PHP安装redis扩