1. 程式人生 > >python關鍵字之 yield

python關鍵字之 yield

Image result for 倫納德

今天來聊聊 python 關鍵字中的 yield,大部分人剛開始學的時候都會對 yield,還有 yield 和 return 之間有些疑惑吧,好,今天就來聊聊

其實這個問題早已在 Stack Overflow 上聊過啦,也有大神給出了非常滿意的答案(讓迷弟心生敬佩)(連結在這裡

不過是英文的,我先把一些比較基礎的 yield 翻譯出來吧

以下是我翻譯的內容:

----------------------------------------------------------------------------------------------------------------------------------------(我是分割線)

為了理解 yield是怎麼操作的,你必須先理解什麼是生成器。不過在此之前,我們先來看看可迭代物件

可迭代物件


當你建立了一個列表,你可以逐項地讀取這個列表。這個過程就是迭代

>>> mylist = [1, 2, 3]
>>> for i in mylist:
...    print(i)
1
2
3

mylist是一個可迭代物件。當你使用一個列表生成式的時候,你建立了一個列表,也就是一個可迭代物件

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
...    print(i)
0
1
4


所有你可以使用 "for...in..."的都是可迭代物件:列表,字串,檔案等等
你經常使用它們因為你可以如你所願的讀取其中的元素,但是你把所有的資料都存貯在記憶體裡,如果你有許多資料的話,這種做法不會是你想要的

生成器

生成器都是可以迭代的,但是你只可以迭代它們一次,因為他們並不是把所有的資料存貯在記憶體中,它是實時的生成資料

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)
0
1
4

看上去都是一樣的,除了使用()而不是 []。但是你不可以再次使用 for i in mygenerator

  因為生成器只能被逆代一次:他們先計算出0,然後就丟掉了0,然後再繼續逐項計算1,計算4


Yield


yield是一個類似 return的關鍵字,不同的是這個函式返回的是一個生成器

>>> def createGenerator():
...    mylist = range(3)
...    for i in mylist:
...        yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4

這個例子沒什麼用途,但如果你的函式會返回一大批你只需要閱讀一次的資料的時候,這是很方便的。

為了精通 yield,你必須理解:當你呼叫這個函式的時候,函式裡的程式碼是不會馬上執行的。這個函式只是返回生成器物件,這有點蹊蹺不是嗎?

那麼,函式的程式碼什麼時候開始執行呢?使用for迭代的時候

現在到了比較的難的一部分:

第一次迭代的時候,你的函式開始執行,從開始到達yield關鍵字,然後返回第一次迭代的值。然後,每次執行這個函式都會繼續執行你在函式內部定義的那個迴圈的下一次,再返回那個值,直到沒有可以返回的值。如果生成器內部沒有定義yield 關鍵詞,這個生成器被認為是空的。也有可能是因為迴圈已經結束或者沒有滿足“If/else”條件

----------------------------------------------------------------------------------------------------------------------------------------(我是分割線)

更深入聊一下:什麼時候使用 field 而不是 return?


yield語句暫停函式的執行,並向呼叫者傳送一個值,但保留足夠的狀態以使函式能夠在其被關閉的位置恢復。 恢復後,該功能在最後一次產量執行後立即繼續執行。 這允許其程式碼隨時間產生一系列值,而不是一次計算它們,並將其像列表一樣傳送回來。

我們來看一個例子:

def simpleGeneratorFun():
    yield 1
    yield 2
    yield 3
 
# Driver code to check above generator function
for value in simpleGeneratorFun(): 
    print(value)
輸出:
1
2
3

return返回一個指定的值給它的呼叫者,而yield可以產生一個值序列。 當要遍歷一個序列但又不想將整個序列儲存在記憶體中的時候,我們應該使用yield

yield用於Python生成器中。 一個生成器函式被定義為一個正常的函式,但是隻要它需要生成一個值,就應該使用 yield 關鍵字而不是return。 如果 def 的 body 包含 yield,則該函式自動成為生成器函式。


寫部落格也參考了一些資料(學習一般都是看英文的):
(1)https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do?page=1&tab=votes#tab-top
(2)http://www.geeksforgeeks.org/use-yield-keyword-instead-return-keyword-python/