你??吹?Python 代碼中的 yield 到底是什么鬼?

首先我們來看下這兩個列表的區(qū)別:

可以看到, list_1 是 [i for i in range(20)] ,而 list_2 是 (i for i in range(20)),主要區(qū)別就是一個是 [] , 一個是 (),而后者就是生成器。
可以看到,當我們去執(zhí)行 list_2 的時候,輸出結果是一個 generator(生成器)對象。
我們可以通過 next() 去調用這個生成器里面的元素:

我們這樣,來計算一下以下這兩個列表生成所需要的時間:
list_1 = [i for i in range(66666666)]list_2 = (i for i in range(66666666))
我們分別把它們放到方法里面執(zhí)行,然后用裝飾器的方式對它們各自的方法執(zhí)行時間做個記錄:

執(zhí)行結果如下:

這是因為使用列表生成式生成的列表,是固定的,也就是說,當我們執(zhí)行 [i for i in range(66666666)] 的時候, list_1 這個列表所封裝的元素個數(shù)就是 66666666 -1 個。
而生成器生成的 list_2 就不是這樣,它是記錄了一定的算法規(guī)則,比如我們這里的 for i in range(66666666) 就是不斷的 +=1 ,生成器只要記住這個規(guī)則就可以了,不需要將全部的數(shù)據(jù)都直接一股腦的裝進 list_2 ,而是等到我們需要的時候,我們去調用的時候,它再去算一下,然后把相應的數(shù)據(jù)返回給我們。
這,就是生成器,記住一點,它是根據(jù)一定的規(guī)律算法生成的,當我們去遍歷它的時候,它可以通過特定的算法不斷的推算出相應的元素,邊運行邊推算結果,從而節(jié)省了很多空間。
體會下下面這兩者的區(qū)別:

yield 和 return 有點相似,return 這個關鍵詞你應該很熟悉吧,在函數(shù)中只要執(zhí)行到這個關鍵詞,就會返回相應的結果并且終止函數(shù)的執(zhí)行:

很好理解,這里返回 3 而不會繼續(xù)返回 hahahahah。
那么 yield 又是怎么樣的呢?咱們繼續(xù)看:

那么我們來看看調用了這個 foo 函數(shù)之后得到的是什么類型:

是的,一個函數(shù)里面如果被定義了 yield ,那么這個函數(shù)就是一個生成器。
我們可以通過 next 方法來使用這個生成器:

可以看到,當我們第一次調用的時候,遇到第一個 yield 的時候就跳出函數(shù)了,第二次調用的時候就是從第 1 個 yield 開始,第三個 yield 結束,以此類推。直到 next 沒有數(shù)據(jù)之后報 StopIteration。
既然它是一個生成器,那么我們就可以遍歷它,我們具體打印出每個具體的元素,看看是什么:


不過呢,我們一般不會這么寫,我剛剛說了,生成器是根據(jù)一定的規(guī)律算法生成的列表,當我們去遍歷它的時候,它可以通過特定的算法不斷的推斷出相應的元素,邊運行邊推算結果,節(jié)省空間。
所以 yield 一般會在 for 循環(huán)語句以一定的規(guī)則生成,舉一個最簡單的例子,生成這么些偶數(shù):

這樣我們在調用 foo 的時候就會得到一個生成器,然后就可以直接遍歷使用。另外,yield 后面可以跟常用的數(shù)據(jù)類型,比如 string,int,dict:

那么當你下次去調用相應的函數(shù)就會得到這樣的 generator,于是就可以:OMG,根據(jù)對應的規(guī)則遍歷它!?

掃一掃
學習 Python 沒煩惱
評論
圖片
表情
