Python中yield的解釋

wklken發表於2015-12-13

翻譯

來源於stackoverflow問答,原文連結 Here

SN上面看到的,順手翻譯下,第一次翻譯,好多地方翻的不是很好 :)


問題:

例如,我想理解以下程式碼

下面是呼叫者

在_get_child_candidates這個函式被呼叫時發生了什麼?返回了一個列表?還是隻返回了一個元素?然後又再次被呼叫?什麼時候呼叫結束?

這段程式碼的來源 Jochen Schulz (jrschulz), who made a great Python library for metric spaces. 完整原始碼連結: here


要了解yield的作用,你必須先明白什麼是生成器,在此之前,你需要了解什麼是可迭代物件(可迭代序列)

迭代

你可以建立一個列表,然後逐一遍歷,這就是迭代

mylist是可迭代的物件,當你使用列表解析時,你建立一個列表,即一個可迭代物件

任何你可用 “for… in…” 處理的都是可迭代物件:列表,字串,檔案….
這些迭代物件非常便捷,因為你可以儘可能多地獲取你想要的東西

但,當你有大量資料並把所有值放到記憶體時,這種處理方式可能不總是你想要的
(but you store all the values in memory and it’s not always what you want when you have a lot of values.)

生成器

生成器是迭代器,但你只能遍歷它一次(iterate over them once)
因為生成器並沒有將所有值放入記憶體中,而是實時地生成這些值

這和使用列表解析地唯一區別在於使用()替代了原來的[]

注意,你不能執行for i in mygenerator第二次,因為每個生成器只能被使用一次: 計算0,並不保留結果和狀態,接著計算1,然後計算4,逐一生成

yield

yield是一個關鍵詞,類似return, 不同之處在於,yield返回的是一個生成器

這個例子並沒有什麼實際作用,僅說明當你知道你的函式將產生大量僅被讀取一次的資料時,使用生成器將是十分有效的做法

要掌握yield,你必須明白 – 當你呼叫這個函式,函式中你書寫的程式碼並沒有執行。這個函式僅僅返回一個生成器物件

這有些狡猾 :-)

然後,在每次for迴圈使用生成器時,都會執行你的程式碼

然後,是比較困難的部分:

第一次函式將會從頭執行,直到遇到yield,然後將返回迴圈的首個值. 然後,每次呼叫,都會執行函式中的迴圈一次,返回下一個值,直到沒有值可以返回

當迴圈結束,或者不滿足”if/else”條件,導致函式執行但不命中yield關鍵字,此時生成器被認為是空的

問題程式碼的解釋

生成器:

呼叫者:

這段程式碼包含幾個靈活的部分:

1.這個迴圈遍讀取歷候選列表,但過程中,候選列表不斷擴充套件:-)

這是一種遍歷巢狀資料的簡明方法,雖然有些危險,你或許會陷入死迴圈中

在這個例子中, candidates.extend(node._get_child_candidates(distance, min_dist, max_dist)) 讀取了生成器產生的所有值, 同時while迴圈產生新的生成器物件加入到列表,因為每個物件作用在不同節點上,所以每個生成器都將生成不同的值

2.列表方法extend() 接收一個生成器,生成器的所有值被新增到列表中

通常,我們傳一個列表作為引數:

但是,在程式碼中,這個函式接受到一個生成器

這樣的做法好處是:

1.你不需要重複讀這些值

2.你可能有海量的子節點,但是不希望將所有節點放入記憶體

並且,可以這麼傳遞生成器作為引數的原因是,Python不關心引數是一個方法還是一個列表

Python接收可迭代物件,對於字串,列表,元組還有生成器,都適用!

這就是所謂的“鴨子型別”(duck typing), 這也是Python如此酷的原因之一, 但這是另一個問題了,對於這個問題……

你可以在這裡完成閱讀,或者讀一點點生成器的進階用法:

控制一個生成器的消耗

這在很多場景都非常有用,例如控制資源的獲取

Itertools

一個很好的工具

itertools模組包含很多處理可迭代物件的具體方法. 例如

複製一個生成器?連線兩個生成器?一行將巢狀列表中值分組?不使用另一個列表進行Map/Zip?
(Ever wish to duplicate a generator? Chain two generators? Group values in a nested list with a one liner? Map / Zip without creating another list?)

只需要使用itertools模組

一個例子,4匹馬賽跑的可能抵達順序

瞭解迭代器的內部機制

迭代過程包含可迭代物件(實現__iter__()方法) 和迭代器(實現__next__()方法)

你可以獲取一個迭代器的任何物件都是可迭代物件,迭代器可以讓你迭代遍歷一個可迭代物件(Iterators are objects that let you iterate on iterables.) [好拗口:]

更多關於這個問題的 how does the for loop work

如果你喜歡這個回答,你也許會喜歡我關於 decoratorsmetaclasses 的解釋

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

Python中yield的解釋 Python中yield的解釋

相關文章