python:理解關鍵字—yield

走川_發表於2017-12-19

前言

為了方便追小說更新擼了一個基於scrapy的爬蟲。在實現過程中使用到了 yield,網上對其的文字描述都很難讓人理解。通過Debug程式碼才瞭解呼叫順序,進而理解了它使用方法。

概念

理解yield作用

我們可以用一個等式來形容其作用:

yeild 函式 = return 生成器(generator) 用同步方式寫非同步

什麼是生成器

生成器 = 可迭代的函式

正常情況下我們可以這樣迭代一個列表

# encoding:UTF-8

def call(i):
    return i * 2

array = [call(0),call(1),call(2)]

for i in array:
    print(i, ",")
複製程式碼

列印結果:

0 ,
2 ,
4 ,
複製程式碼

以上的程式碼,適合在資料量小的情況下執行,假如在海量資料的場景下,這樣的寫法將對記憶體造成很大的壓力。因為列表內所有資料都同時載入在記憶體中。

而python的生成器則完美的解決了這一問題,它不需要將所有的值同時載入,它只提供了一個生成資料的方式, 而且它是可迭代

# encoding:UTF-8

def call(i):
    return i * 2

def generator(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

def call(i):
    return i * 2

def generator(n):
    for i in range(n):
        yield call(i)
        print("generate i=", i)
    print("end.")

for i in generator(3):
    print(i, ",")
複製程式碼

在我們的預期中,我們的預期執行順序是

upload successful
這樣的話執行結果應該是這樣:

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.
複製程式碼

那麼意味著它的執行順序是這樣:

upload successful
debug後也發現的確如此。

可以發現,只要執行到yield關鍵字都會先return,在外層執行完畢後,再執行yield之後下一條指令。

啟發

當我們處理資料量大的事物的時候,可以效仿關鍵字yield這樣的思路:持有索引或者其他可檢索的id,在需要的時候再去通過構造器或者其他工具獲取

相關文章