1 yield from 2 yield from x 表達式對 x 對象所作的第一件事是,調用 iter(x),從中獲取迭代器。因 3 此, x 能夠是任何可迭代的對象。 4 但是,若是 yield from 結構惟一的做用是替代產出值的嵌套 for 循環,這個結構頗有 5 可能不會添加到 Python 語言中。 yield from 結構的本質做用沒法經過簡單的可迭代對象 6 說明,而要發散思惟,使用嵌套的生成器。所以,引入 yield from 結構的 PEP 380 才起 7 了「Syntax for Delegating to a Subgenerator」(「把職責委託給子生成器的句法」)這個標題。 8 yield from 的主要功能是打開雙向通道,把最外層的調用方與最內層的子生成器鏈接起 9 來,這樣兩者能夠直接發送和產出值,還能夠直接傳入異常,而不用在位於中間的協程中 10 添加大量處理異常的樣板代碼。有了這個結構,協程能夠經過之前不可能的方式委託職責。 11 若想使用 yield from 結構,就要大幅改動代碼。爲了說明須要改動的部分, PEP 380 使 12 用了一些專門的術語。 13 14 委派生成器 15 包含 yield from <iterable> 表達式的生成器函數。 16 17 子生成器 18 從 yield from 表達式中 <iterable> 部分獲取的生成器。這就是 PEP 380 的標題 19 (「Syntax for Delegating to a Subgenerator」)中所說的「子生成器」(subgenerator)。 20 21 調用方 22 PEP 380 使用「調用方」這個術語指代調用委派生成器的客戶端代碼。 23 24 子生成器多是簡單的迭代器,只實現了 __next__ 方法;可是, yield from 也能處理這種子生成器。 25 不過,引入 yield from 結構的目的是爲了支持實現了 __next__、 send、 close 和throw 方法的生成器。 26 27 若是子生成器不終止,委派生成器會在 yield from 表達式處永遠暫停。若是是這樣,程序不會向前執行, 28 由於 yield from(與 yield 同樣)把控制權轉交給客戶代碼(即,委派生成器的調用方)了。顯然, 29 確定有任務沒法完成. 30 31 由於委派生成器至關於管道,因此能夠把任意數量個委派生成器鏈接在一塊兒:一個委派生成器使用 32 yield from 調用一個子生成器,而那個子生成器自己也是委派生成器,使用 yield from 33 調用另外一個子生成器,以此類推。最終,這個鏈條要以一個只使用 yield 表達式的簡單生成器結束; 34 不過,也能以任何可迭代的對象結束. 35 36 任何 yield from 鏈條都必須由客戶驅動,在最外層委派生成器上調用 next(...) 函數 37 或 .send(...) 方法。能夠隱式調用,例如使用 for 循環。 38 39 批准後的 PEP 380 在「Proposal」一節(https://www.python.org/dev/peps/pep-0380/#proposal) 40 分六點說明了 yield from 的行爲。 41 a, 子生成器產出的值都直接傳給委派生成器的調用方(即客戶端代碼)。 42 b, 使用 send() 方法發給委派生成器的值都直接傳給子生成器。若是發送的值是 43 None,那麼會調用子生成器的 __next__() 方法。若是發送的值不是 None,那麼會 44 調用子生成器的 send() 方法。若是調用的方法拋出 StopIteration 異常,那麼委 45 派生成器恢復運行。任何其餘異常都會向上冒泡,傳給委派生成器。 46 c, 生成器退出時,生成器(或子生成器)中的 return expr 表達式會觸發 47 StopIteration(expr) 異常拋出。 48 d, yield from 表達式的值是子生成器終止時傳給 StopIteration 異常的第一個參數。 49 e, yield from 結構的另外兩個特性與異常和終止有關。傳入委派生成器的異常, 50 除了 GeneratorExit 以外都傳給子生成器的 throw() 方法。若是調用 throw() 51 方法時拋出 StopIteration 異常,委派生成器恢復運行。 StopIteration 以外的 52 異常會向上冒泡,傳給委派生成器。 53 f, 若是把 GeneratorExit 異常傳入委派生成器,或者在委派生成器上調用 close() 方 54 法,那麼在子生成器上調用 close() 方法,若是它有的話。若是調用 close() 方法 55 致使異常拋出,那麼異常會向上冒泡,傳給委派生成器;不然,委派生成器拋出 GeneratorExit 異常。