深入理解 Python yield

來源:互聯網
上載者:User

標籤:The   函數   name   pass   param   ams   接收   python   ace   

78915518

 

python2和python3是不相容的,通篇環境都是python3.6

簡單的yield執行個體

以前只是粗略的知道yield可以用來為一個函數傳回值塞資料,比如下面的例子:

def addlist(alist):    for i in alist:        yield i + 1

 

取出alist的每一項,然後把i + 1塞進去。然後通過調用取出每一項:

alist = [1, 2, 3, 4]for x in addlist(alist):    print(x)

這的確是yield應用的一個例子,但是,看過很多東西,並自己反覆體驗後,對yield有了一個全新的理解,其中這篇算是精品了。

包含yield的函數

假如你看到某個函數包含了yield,這意味著這個函數已經是一個Generator,它的執行會和其他普通的函數有很多不同。比如下面的簡單的函數:

def h():    print(‘study yield‘)    yield 5    print(‘go on!‘)h()

 

可以看到,調用h()之後,print 語句並沒有執行!這就是yield。具體的內容後面會越來越清晰,包括yield的工作原理。

yield是一個運算式

python 2.5以前,yield是一個語句,我也沒有考證,因為早都不用了,現在yield是一個運算式:

m = yield 5

運算式(yield 5)的傳回值將賦值給m,所以,m = 5 肯定是錯的。

那麼如何擷取(yield 5)的傳回值呢?需要用到send(msg)

yield工作原理

揭曉yield的工作原理,需要配合next()函數。上面的h()被調用後並沒有執行,因為它有yield運算式,通過next()可以恢複Generator執行,直到下一個yield

def h():    print(‘study yield‘)    yield 5    print(‘go on!‘)c = h()d1 = next(c)  # study yieldd2 = next(c)"""study yieldgo on!Traceback (most recent call last):  File "D:/idea/workspace/pythonSpace/PythonDemo/static/yield_demo.py", line 35, in <module>    d2 = next(c)StopIteration"""
  • 1
  • 2
  • 3
  • 4

next()被調用後,h()開始執行,直到遇到yield 5

因此輸出結果是:study yield

當我們再次調用next()時,會繼續執行,直到找到下一個yield。由於後面沒有yield了,因此會拋出異常:

study yieldgo on!Traceback (most recent call last):  File "D:/idea/workspace/pythonSpace/PythonDemo/static/yield_demo.py", line 35, in <module>    d2 = next(c)StopIteration

 

send(msg) 與 next()

瞭解了next()如何讓包含yield的函數執行後,我們再來看另外一個非常重要的函數send(msg)

其實next()send()在一定意義上作用是相似的

區別

send()可以傳遞yield的值

next()只能傳遞None

所以next() 和 send(None)作用是一樣的。

def s():    print(‘study yield‘)    m = yield 5    print(m)    d = yield 16    print(‘go on!‘)c = s()s_d = next(c)  # 相當於send(None)c.send(‘Fighting!‘)  # (yield 5)運算式被賦予了‘Fighting!‘

 

輸出的結果為:

study yieldFighting!

 

注意 產生器剛啟動時(第一次調用),請使用next()語句或是send(None),不能直接發送一個非None的值,否則會報TypeError,因為沒有yield語句來接收這個值。

send(msg) 與 next()的傳回值

send(msg) 和 next() 的傳回值比較特殊,是下一個yield運算式的參數(yield 5,則返回 5)。

到這裡,第一個例子中,通過for i in alist 遍曆 Generator,其實是每次都調用了next(),而每次next()的傳回值正是yield的參數:

def s():    print(‘study yield‘)    m = yield 5    print(m)    d = yield 16    print(‘go on!‘)c = s()s_d1 = next(c)  # 相當於send(None)s_d2 = c.send(‘Fighting!‘)  # (yield 5)運算式被賦予了‘Fighting!‘print(‘My Birth Day:‘, s_d1, ‘.‘, s_d2)

 

輸出結果:

study yieldFighting!My Birth Day: 5 . 16

 

中斷Generator

上面的例子中,當沒有可執行程式的時候,會拋出一個StopIteration, 開發過程中,中斷Generator是一個非常靈活的技巧

throw

通過拋出一個GeneratorExit異常來終止Generator。

close

close的作用和throw是一樣的,看它的源碼,可以發現,它和raise一球樣

def throw(self, type, value=None, traceback=None):    ‘‘‘Used to raise an exception inside the generator.‘‘‘    # 用於在產生器中拋出一個異常。    passdef close(self):    ‘‘‘Raises new GeneratorExit exception inside the generator to terminate the iteration.‘‘‘    # 在產生器中產生新的GeneratorExit異常來終止迭代。    pass

 

其實最後一個中斷產生器可以忽略的,在開發過程中,不可避免的要用到這些,但是Python3內部已經做得很好了,一般不太需要手動去做這件事情。

demo地址

https://github.com/seeways/PythonDemo/blob/master/static/yield_demo.py

深入理解 Python yield

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.