#pep380 #1. RESULT = yield from EXPR能夠簡化成下面這樣 #一些說明 """ _i:子生成器,同時也是一個迭代器 _y:子生成器生產的值 _r:yield from 表達式最終的值 _s:調用方經過send()發送的值 _e:異常對象 """ _i = iter(EXPR) # EXPR是一個可迭代對象,_i實際上是子生成器; try: _y = next(_i) # 預激子生成器,把產出的第一個值存在_y中; except StopIteration as _e: _r = _e.value # 若是拋出了`StopIteration`異常,那麼就將異常對象的`value`屬性保存到_r,這是最簡單的狀況的返回值; else: while 1: # 嘗試執行這個循環,委託生成器會阻塞,這裏是委託生成器在執行 _s = yield _y # 生產子生成器的值,等待調用方`send()`值,發送過來的值將保存在_s中;委託生成器yield出子生成器的值到調用方 try: _y = _i.send(_s) # 轉發_s,而且嘗試向下執行; except StopIteration as _e: _r = _e.value # 若是子生成器拋出異常,那麼就獲取異常對象的`value`屬性存到_r,退出循環,恢復委託生成器的運行; break RESULT = _r # _r就是整個yield from表達式返回的值。 """ 1. 子生成器可能只是一個迭代器,並非一個做爲協程的生成器,因此它不支持.throw()和.close()方法; 2. 若是子生成器支持.throw()和.close()方法,可是在子生成器內部,這兩個方法都會拋出異常; 3. 調用方讓子生成器本身拋出異常 4. 當調用方使用next()或者.send(None)時,都要在子生成器上調用next()函數,當調用方使用.send()發送非 None 值時,才調用子生成器的.send()方法; """ _i = iter(EXPR) try: _y = next(_i) except StopIteration as _e: _r = _e.value else: while 1: try: _s = yield _y except GeneratorExit as _e: try: _m = _i.close except AttributeError: pass else: _m() raise _e except BaseException as _e: _x = sys.exc_info() try: _m = _i.throw except AttributeError: raise _e else: try: _y = _m(*_x) except StopIteration as _e: _r = _e.value break else: try: if _s is None: _y = next(_i) else: _y = _i.send(_s) except StopIteration as _e: _r = _e.value break RESULT = _r """ 看完代碼,咱們總結一下關鍵點: 1. 子生成器生產的值,都是直接傳給調用方的;調用方經過.send()發送的值都是直接傳遞給子生成器的;若是發送的是 None,會調用子生成器的__next__()方法,若是不是 None,會調用子生成器的.send()方法; 2. 子生成器退出的時候,最後的return EXPR,會觸發一個StopIteration(EXPR)異常; 3. yield from表達式的值,是子生成器終止時,傳遞給StopIteration異常的第一個參數; 4. 若是調用的時候出現StopIteration異常,委託生成器會恢復運行,同時其餘的異常會向上 "冒泡"; 5. 傳入委託生成器的異常裏,除了GeneratorExit以外,其餘的全部異常所有傳遞給子生成器的.throw()方法;若是調用.throw()的時候出現了StopIteration異常,那麼就恢復委託生成器的運行,其餘的異常所有向上 "冒泡"; 6. 若是在委託生成器上調用.close()或傳入GeneratorExit異常,會調用子生成器的.close()方法,沒有的話就不調用。若是在調用.close()的時候拋出了異常,那麼就向上 "冒泡",不然的話委託生成器會拋出GeneratorExit異常。 """