python yield from (二)

#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異常。

"""
相關文章
相關標籤/搜索