昨天看了許多條博客,同時問了大佬一些心中的疑惑,對這個yield心中有了些許的理解,雖然可能沒有理解到他的內涵,但至少在使用時該如何使用還是有了些許了解,因此決定寫出來分享
首先我們得了解一個東西叫迭代器,通常的for…in…循環中,in后面是一個數組,這個數組就是一個可迭代對象,類似的還有鏈表,字符串,文件。它可以是mylist = [1, 2, 3],也可以是mylist = [x*x for x in range(3)]。 它的缺陷是所有數據都在內存中,如果有海量數據的話將會非常耗內存。他們可以從內容從中一個一個的讀取,這就是迭代。
接着我們需要了解迭代器里的一個特殊——生成器,生成器也是一個可以迭代的對象,但是生成器每個只能迭代一次(至於為什么后面會講),這是他特殊的原因。因為用的時候才生成。比如 mygenerator = (x*x for x in range(3)),注意這里用到了(),它就不是數組,而上面的例子是[]。生成器這里用的是小括號,而迭代器用的是中括號。
好了接下來得講下他們的方法,不管是生成器還是迭代器,都可以使用他的方法,就是next(這個方法在python2里面是使用的時候是方法c.next(),在python3里面變為了函數next(c)),但是由於迭代器可以自動進行,相當於里面已經內嵌了這個方法,生成一個迭代器他可以自動往后迭代,但是生成器不一樣,生成一個生成器的時候,他是定在初始狀態的,這就需要我們的next來一步一步推動他們。他們還有一種方法是send(),這個相當於在next功能的基礎上,再加了一個傳遞的功能,他可以傳遞參數給yield表達式,所以send(None)就相當於next參數。
現在我們可以來談談yield了,其實yield就相當於一個return,只是return返回的是值,但是yield返回的是生成器,除了這點其他都一樣,所以return也好yield也好都只能用在函數中,不要出現這種代碼了:
for i in range(5): return i
所以要試驗yield要在函數里實驗,我們可以試着構造一個生成器:
def y_test(x): for i in range(x): yield i print(i) y_test(3)
我們試着輸出結果,卻發現沒有輸出,這是因為生成了一個生成器,而且生成的生成器是在初始狀態,咱們還沒給他下指令他就不會開始生成,所以現在我們給他一個指令
def y_test(x): for i in range(x): yield i print(i) y_test(3) c = y_test(3) next(c)
誒,我們現在改造了后為什么還是顯示沒有輸出,現在生成器是生成了但別忘了這是一個相當於return的函數,他實際上已經把值傳進了內存,但是沒有顯示出來,我們可以用一個print把他顯示出來
def y_test(x): for i in range(x): yield i print(i) y_test(3) c = y_test(3) print(next(c))
現在我們就會看到它顯示出來了(range這個函數生成了從1到n-1得數,比如range(5)生成了0.1.2.3.4)
好,那么接下來你可能又會有問題了,為什么這個只生成了第一個數啊,不應該是遍歷把所有的輸出來嗎,這就是yield的作用了,這是因為生成了生成器,我們next他一次,他也就只會往前走一次,第二次就不走了,那我們就再來一次next看看會怎樣:
def y_test(x): for i in range(x): yield i print(i) y_test(3) c = y_test(3) print(next(c)) print(next(c))
這時候出現了三個值,這就要繼續解釋yield的原因了,每次我們使用一次next,他都會執行到第一個yield結束的位置,第二次用next推動他執行時,他就會從上一個yield執行完成的位置開始執行到下一個yield執行完成,在這里是在for循環里,下一個yield就是第二個循環里的yield,雖然是一樣的語句,但是他們所在的循環次數不一樣,所以yield就相當於返回值的同時,記住當前運行到的位置,下一次運行就從上一次運行到的位置開始運行,這也是為什么他只能遍歷一遍的原因,因為在第二個next執行的時候,第一個next里的內容已經被拋掉了,內存里只有第二個yield執行的內容。
我們可以再看一例子來加深理解:
def f(x): for i in range(x): yield i print (i) yield i+1 c = f(5) print(next(c)) print(next(c)) print(next(c))
根據上文的理解會輸出四個值
符合前面的猜想,最后讓我們來用一個斐波那契數列的例子來結束全文吧:
def fib(x): yield 1 a,b = 1,1 while x: a,b = b,a+b yield a x=x-1 for i in fib(5): print(i) >>>runfile('F:/Python/exercise/pygame/yield_text.py', wdir='F:/Python/exercise/pygame') 1 1 2 3 5 8