為了方便追**更新擼了乙個基於scrapy的爬蟲。在實現過程中使用到了yield,網上對其的文字描述都很難讓人理解。通過debug**才了解呼叫順序,進而理解了它使用方法。
我們可以用乙個等式來形容其作用:
yeild 函式 = return 生成器(generator)用同步方式寫非同步
生成器 = 可迭代的函式正常情況下我們可以這樣迭代乙個列表
# encoding:utf-8
defcall
(i):
return i * 2
array = [call(0),call(1),call(2)]
for i in array:
print(i, ",")
複製**
列印結果:
0 ,
2 ,4 ,
複製**
以上的**,適合在資料量小的情況下執行,假如在海量資料的場景下,這樣的寫法將對記憶體造成很大的壓力。因為列表內所有資料都同時載入在記憶體中。
而python的生成器則完美的解決了這一問題,它不需要將所有的值同時載入,它只提供了乙個生成資料的方式, 而且它是可迭代
# encoding:utf-8
defcall
(i):
return i * 2
defgenerator
(n):
for i in range(n):
yield call(i)
for i in generator(3):
print(i, ",")
複製**
列印結果:
0 ,
2 ,4 ,
複製**
可以看到 generator 做的事情很簡單:迴圈生成了0到2相對應的值。而yield的作用就是提供生成器給外部。
這樣做的好處就在於每次值都是按需生成的,且生成完不會停駐在記憶體中。
值得一提的就是yield的呼叫順序也是很清奇的,它的呼叫順序和我們常見的簡單的自上而下。 我們在以上的demo中加入幾行print
# encoding:utf-8
defcall
(i):
return i * 2
defgenerator
(n):
for i in range(n):
yield call(i)
print("generate i=", i)
print("end.")
for i in generator(3):
print(i, ",")
複製**
在我們的預期中,我們的預期執行順序是
這樣的話執行結果應該是這樣:
generate i= 0
0 ,generate i= 1
2 ,generate i= 2
4 ,end.
複製**
而它的結果執行結果卻是這樣:
0 ,
generate i= 0
2 ,generate i= 1
4 ,generate i= 2
end.
複製**
那麼意味著它的執行順序是這樣:
debug後也發現的確如此。
可以發現,只要執行到yield關鍵字都會先return,在外層執行完畢後,再執行yield之後下一條指令。
當我們處理資料量大的事物的時候,可以效仿關鍵字yield這樣的思路:持有索引或者其他可檢索的id,在需要的時候再去通過構造器或者其他工具獲取
this關鍵字理解
public class test implements runnable synchronized void m1 throws interruptedexception synchronized void m2 throws interruptedexception override publi...
Python 關鍵字 yield 的理解
為了更好地理解關鍵字yield的用法,首先需要理解迭代器 iterator 與生成器 generator 的區別。當建立列表中的元素時,我們可以使用for迴圈 myiterator x x for x in range 3 print myiterator 0,1,4 因此我們稱列表是可迭代的 it...
C virtual關鍵字理解
在c 語言中,從 到程式的執行,要經歷編譯和連線,針對這兩個不同的階段,c 設計了不同的機制,其中vitual和inline就是區分編譯器工作和鏈結器工作的標誌 inline很容易理解,生命為inline的函式在編譯階段即被展開成 而非inline的函式採用執行時鏈結的方式處理 vitual關鍵字,...