天天看點

生成器簡述

生成器

生成器是一類特殊的疊代器

将每次疊代傳回數值的return換成了yield,此時新定義的函數便不再是函數,而是一個生成器了。簡單來說:隻要在def中有yield關鍵字的 就稱為 生成器

In [30]: def fib(n):
   ....:     current = 0
   ....:     num1, num2 = 0, 1
   ....:     while current < n:
   ....:         num = num1
   ....:         num1, num2 = num2, num1+num2
   ....:         current += 1
   ....:         yield num
   ....:     return 'done'
           
In [39]: g = fib(5)

In [40]: while True:
   ....:     try:
   ....:         x = next(g)
   ....:         print("value:%d"%x)      
   ....:     except StopIteration as e:
   ....:         print("生成器傳回值:%s"%e.value)
   ....:         break
   ....:     
value:1
value:1
value:2
value:3
value:5
生成器傳回值:done
           

生成器在yield時,将對應的值送到主函數調用next()的x中,暫停生成器,同時保留原來的資料參數。等到再次執行next()時,生成器在原來暫停的位置,繼續執行。

總結

  • 使用了yield關鍵字的函數不再是函數,而是生成器。(使用了yield的函數就是生成器)
  • yield關鍵字有兩點作用:
    • 儲存目前運作狀态(斷點),然後暫停執行,即将生成器(函數)挂起
    • 将yield關鍵字後面表達式的值作為傳回值傳回,此時可以了解為起到了return的作用
  • 可以使用next()函數讓生成器從斷點處繼續執行,即喚醒生成器(函數)
  • Python3中的生成器可以使用return傳回最終運作的傳回值,而Python2中的生成器不允許使用return傳回一個傳回值(即可以使用return從生成器中退出,但return後不能有任何表達式)。

使用send喚醒

我們除了可以使用next()函數來喚醒生成器繼續執行外,還可以使用send()函數來喚醒執行。使用send()函數的一個好處是可以在喚醒的同時向斷點處傳入一個附加資料。

In [10]: def gen():
   ....:     i = 0
   ....:     while i<5:
   ....:         temp = yield i
   ....:         print(temp)
   ....:         i+=1
   ....:
           

使用send

In [43]: f = gen()

In [44]: next(f)
Out[44]: 0

In [45]: f.send('haha')
haha
Out[45]: 1
           

next将yield的i值傳到調用next指向的變量,然後調用send将’haha’傳入給temp,同時喚醒生成器,從next暫停處順序執行,再次執行到yield處,将i值傳到調用send指向的變量。