詳解Python3中yield產生器的用法

來源:互聯網
上載者:User
任何使用yield的函數都稱之為產生器,如:

def count(n):   while n > 0:     yield n  #產生值:n     n -= 1 

另外一種說法:產生器就是一個返回迭代器的函數,與普通函數的區別是產生器包含yield語句,更簡單點理解產生器就是一個迭代器。

使用yield,可以讓函數產生一個序列,該函數返回的物件類型是"generator",通過該對象連續調用next()方法返回序列值。

c = count(5) c.__next__() #python 3.4.3要使用c.__next__()不能使用c.next()>>> 5 c.__next__() >>>4 


產生器函數只有在調用__next()__方法的時候才開始執行函數裡面的語句,比如:

def count(n):   print ( "cunting" )  while n > 0:     yield n  #產生值:n     n -= 1 

在調用count函數時:c=count(5),並不會列印"counting"只有等到調用c.__next__()時才真正執行裡面的語句。每次調用__next__()方法時,count函數會運行到語句yield n處為止,__next__()的傳回值就是產生值n,再次調用__next__()方法時,函數繼續執行yield之後的語句(熟悉Java的朋友肯定知道Thread.yield()方法,作用是暫停當前線程的運行,讓其他線程執行),如:

def count(n):   print ("cunting" )   while n > 0:     print ('before yield')     yield n  #產生值:n     n -= 1     print ('after yield' )

上述代碼在第一次調用__next__方法時,並不會列印"after yield"。如果一直調用__next__方法,當執行到沒有可迭代的值後,程式就會報錯:

Traceback (most recent call last): File "", line 1, in StopIteration
所以一般不會手動的調用__next__方法,而使用for迴圈:

for i in count(5):   print (i),  

執行個體: 用yield產生器類比Linux中命令:tail -f file | grep python 用於尋找監控記錄檔中出現有python字樣的行。

import time  def tail(f):    f.seek(0,2)#移動到檔案EOF   while True:      line = f.readline() #讀取檔案中新的文本行     if not line:        time.sleep(0.1)        continue      yield line    def grep(lines,searchtext):    for line in lines:      if searchtext in line:        yield line  flog = tail(open('warn.log'))  pylines = grep(flog,'python')  for line in pylines:    print ( line, ) #當此程式運行時,若warn.log檔案中末尾有新增一行,且該一行包含python,該行就會被列印出來 #若開啟warn.log時,末尾已經有了一行包含python,該行不會被列印,因為上面是f.seek(0,2)移動到了檔案EOF處 #故,上面程式實現了tail -f warn.log | grep 'python'的功能,動態即時檢測warn.log中是否新增現了 #新的行,且該行包含python  


用yield實現斐波那契數列:

def fibonacci():   a=b=1   yield a   yield b   while True:     a,b = b,a+b     yield b 

調用:

for num in fibonacci():   if num > 100:     break   print (num), 

yield中return的作用:
作為產生器,因為每次迭代就會返回一個值,所以不能顯示的在產生器函數中return 某個值,包括None值也不行,否則會拋出“SyntaxError”的異常,但是在函數中可以出現單獨的return,表示結束該語句。
通過固定長度的緩衝區不斷讀檔案,防止一次性讀取出現記憶體溢出的例子:

def read_file(path):   size = 1024   with open(path,'r') as f:     while True:       block = f.read(SIZE)       if block:         yield block       else:         return 

如果是在函數中return 具體某個值,就直接拋異常了

>>> def test_return(): ...   yield 4 ...   return 0 ...  File "", line 3 SyntaxError: 'return' with argument inside generator 

例子

下面來看幾段程式碼範例:

例1:

>>> def mygenerator(): ...   print 'start...' ...   yield 5 ...  >>> mygenerator()      //在此處調用,並沒有列印出start...說明存在yield的函數沒有被運行,即暫停  >>> mygenerator().next()   //調用next()即可讓函數運行. start... 5 >>>  

如一個函數中出現多個yield則next()會停止在下一個yield前,見例2:

例2:

>>> def fun2(): ...   print 'first' ...   yield 5 ...   print 'second' ...   yield 23 ...   print 'end...' ...  >>> g1 = fun2() >>> g1.next()       //第一次運行,暫停在yield 5        first 5 >>> g1.next()       //第二次運行,暫停在yield 23 second 23 >>> g1.next()       //第三次運行,由於之後沒有yield,再次next()就會拋出錯誤 end... Traceback (most recent call last):  File "", line 1, in  StopIteration >>> 

為什麼yield 5會輸出5,yield 23會輸出23?
我們猜測可能是因為yield是運算式,存在傳回值.
那麼這是否可以認為yield 5的傳回值一定是5嗎?實際上並不是這樣,這個與send函數存在一定的關係,這個函數實質上與next()是相似的,區別是send是傳遞yield運算式的值進去,而next不能傳遞特定的值,只能傳遞None進去,因此可以認為g.next()和g.send(None)是相同的。見例3:

例3:

>>> def fun(): ...   print 'start...' ...   m = yield 5 ...   print m ...   print 'middle...' ...   d = yield 12 ...   print d ...   print 'end...' ...  >>> m = fun()       //建立一個對象 >>> m.next()        //會使函數執行到下一個yield前 start... 5 >>> m.send('message')   //利用send()傳遞值 message          //send()傳遞進來的  middle... 12 >>> m.next() None            //可見next()傳回值為空白 end... Traceback (most recent call last):  File "", line 1, in  StopIteration 
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.