標籤:簡歷 png 理解 return 異常 視窗 解釋 pycharm 技術分享
# 範例代碼
def yield_test(n): for i in range(n): yield call(i) print("i=",i) #做一些其它的事情 print("do something.") print("end.")def call(i): return i*2#使用for迴圈for i in yield_test(5): print(i,",")
最近在scrapy爬蟲方面接觸了很多yield,找了很多網上的資料,很多大神都給出了很透徹的理解方法。但是由於我是菜鳥一個,對於一些很專業的解釋看得似懂非懂。於是乎找了一段代碼,自己在pycharm中一步步調試,終於弄懂了yield的工作原理。
範例代碼中定義了兩個方法yield_test以及call,將會在接下來的迭代中調用。
首先,我們將一個參數“5”傳進yield_test方法中,代碼將會執行到以下步驟。
for i in range(n):
代碼將會生產一個[0,1,2,3,4]的列表,將會在該列表中進行迭代,此時i=0,開始進行迭代
代碼運行到
yield call(i)
時,將會將i=0傳入到 call()方法中,返回一個運算結果"0"
接下來產生器yield將會執行一個類似return的操作,將i=0返回到
for i in yield_test(5): print(i,",")
中,此時將會執行 print(i,",")語句,在Console視窗輸出
完成以上的結果輸出之後,由於yield的機制,下一次迭代時,從上一次迭代遇到的yield後面的代碼開始執行
此時代碼將會返回到以下語句中繼續迭代
print("i=",i)
Console視窗將會繼續列印出第二條結果
執行完畢之後,將會繼續在yield_test方法中進行第二次迭代
此時i的值將會由0變為1 PS:前面產生的列表就是[0,1,2,3,4],剛開始是0,下一次迭代就是1啦
yield將會重複進行迭代,將1傳到call()方法,計算完成後返回到主迴圈裡面繼續輸出 print(i,",") 然後在根據yield的特性返回到 print("i=",i) 輸出到Console視窗中,以此類推。
總結,引用其他大神總結,yield的特性如下:
- 通常的for...in...迴圈中,in後面是一個數組,這個數組就是一個可迭代對象,類似的還有鏈表,字串,檔案。它可以是mylist = [1, 2, 3],也可以是mylist = [x*x for x in range(3)]。
它的缺陷是所有資料都在記憶體中,如果有海量資料的話將會非常耗記憶體。
- 產生器是可以迭代的,但只可以讀取它一次。因為用的時候才產生。比如 mygenerator = (x*x for x in range(3)),注意這裡用到了(),它就不是數組,而上面的例子是[]。
- 我理解的產生器(generator)能夠迭代的關鍵是它有一個next()方法,工作原理就是通過重複調用next()方法,直到捕獲一個異常。可以用上面的mygenerator測試。
- 帶有 yield 的函數不再是一個普通函數,而是一個產生器generator,可用於迭代,工作原理同上。
- yield 是一個類似 return 的關鍵字,迭代一次遇到yield時就返回yield後面的值。重點是:下一次迭代時,從上一次迭代遇到的yield後面的代碼開始執行。
- 簡要理解:yield就是 return 返回一個值,並且記住這個返回的位置,下次迭代就從這個位置後開始。
- 帶有yield的函數不僅僅只用於for迴圈中,而且可用於某個函數的參數,只要這個函數的參數允許迭代參數。比如array.extend函數,它的原型是array.extend(iterable)。
- send(msg)與next()的區別在於send可以傳遞參數給yield運算式,這時傳遞的參數會作為yield運算式的值,而yield的參數是返回給調用者的值。——換句話說,就是send可以強行修改上一個yield運算式值。比如函數中有一個yield賦值,a = yield 5,第一次迭代到這裡會返回5,a還沒有賦值。第二次迭代時,使用.send(10),那麼,就是強行修改yield 5運算式的值為10,本來是5的,那麼a=10
- send(msg)與next()都有傳回值,它們的傳回值是當前迭代遇到yield時,yield後面運算式的值,其實就是當前迭代中yield後面的參數。
- 第一次調用時必須先next()或send(None),否則會報錯,send後之所以為None是因為這時候沒有上一個yield(根據第8條)。可以認為,next()等同於send(None)。
以上是個人對yield的一些簡歷,如有表達錯誤,希望指正。
其實很多看起來很難的東西,把它抄過來,然後在偵錯模式中一步一步地去觀察代碼的運行情況,觀察變數的變化,這樣對理解一樣新事物會有很大的協助(很顯然是廢話 = =!)
關於Python中yield的一些個人見解