徹底理解Python中的yield關鍵字
閱讀別人的python源碼時碰到了這個yield這個關鍵字,各種搜索終于搞懂了,在此做一下總結:
- 通常的for...in...循環(huán)中,in后面是一個數組,這個數組就是一個可迭代對象,類似的還有鏈表,字符串,文件。它可以是mylist = [1, 2, 3],也可以是mylist = [x*x for x in range(3)]。它的缺陷是所有數據都在內存中,如果有海量數據的話將會非常耗內存。
- 生成器是可以迭代的,但只可以讀取它一次。因為用的時候才生成。比如 mygenerator = (x*x for x in range(3)),注意這里用到了(),它就不是數組,而上面的例子是[]。
- 我理解的生成器(generator)能夠迭代的關鍵是它有一個next()方法,工作原理就是通過重復調用next()方法,直到捕獲一個異常??梢杂蒙厦娴膍ygenerator測試。
- 帶有 yield 的函數不再是一個普通函數,而是一個生成器generator,可用于迭代,工作原理同上。
- yield 是一個類似 return 的關鍵字,迭代一次遇到y(tǒng)ield時就返回yield后面(右邊)的值。重點是:下一次迭代時,從上一次迭代遇到的yield后面的代碼(下一行)開始執(zhí)行。
- 簡要理解:yield就是 return 返回一個值,并且記住這個返回的位置,下次迭代就從這個位置后(下一行)開始。
- 帶有yield的函數不僅僅只用于for循環(huán)中,而且可用于某個函數的參數,只要這個函數的參數允許迭代參數。比如array.extend函數,它的原型是array.extend(iterable)。
- send(msg)與next()的區(qū)別在于send可以傳遞參數給yield表達式,這時傳遞的參數會作為yield表達式的值,而yield的參數是返回給調用者的值?!獡Q句話說,就是send可以強行修改上一個yield表達式值。比如函數中有一個yield賦值,a = yield 5,第一次迭代到這里會返回5,a還沒有賦值。第二次迭代時,使用.send(10),那么,就是強行修改yield 5表達式的值為10,本來是5的,那么a=10
- send(msg)與next()都有返回值,它們的返回值是當前迭代遇到y(tǒng)ield時,yield后面表達式的值,其實就是當前迭代中yield后面的參數。
- 第一次調用時必須先next()或send(None),否則會報錯,send后之所以為None是因為這時候沒有上一個yield(根據第8條)。可以認為,next()等同于send(None)。
代碼示例1:
#encoding:UTF-8
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循環(huán)
for i in yield_test(5):
print(i,",")
結果是:
>>>
0 ,
i= 0
2 ,
i= 1
4 ,
i= 2
6 ,
i= 3
8 ,
i= 4
do something.
end.
>>>
理解的關鍵在于:下次迭代時,代碼從yield的下一跳語句開始執(zhí)行。
代碼示例2:
def node._get_child_candidates(self, distance, min_dist, max_dist):
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
與前面不同的是,這個函數中沒有for循環(huán),但它依然可以用于迭代。
node._get_child_candidates函數中有yield,所以它變成了一個迭代器,可以用于迭代。
執(zhí)行第一次迭代時(其實就是調用next()方法),如果有左節(jié)點并且距離滿足要求,會執(zhí)行第一個yield,這時會返回self._leftchild并完成第一個迭代。
執(zhí)行第二次迭代時,從第一個yield后面開始,如果有右節(jié)點并且距離滿足要求,會執(zhí)行第二個yield,這時會返回self._rightchild并完成第一個迭代。
執(zhí)行第三次迭代時,第二個yield后再無代碼,捕獲異常,退出迭代。
調用過程:
result, candidates = list(), [self]
while candidates:
node = candidates.pop()
distance = node._get_dist(obj)
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
上面的node._get_child_candidates(self, distance, min_dist, max_dist)是放在extend()函數中作為參數的,為什么可以這么用,就因為extend函數的參數不僅僅支持array,只要它是一個迭代器就可以。它的原型是array.extend(iterable)。
代碼示例3:

總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。如果你想了解更多相關內容請查看下面相關鏈接
相關文章
在Python中使用K-Means聚類和PCA主成分分析進行圖像壓縮
這篇文章主要介紹了在Python中使用K-Means聚類和PCA主成分分析進行圖像壓縮,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-04-04
在django中form的label和verbose name的區(qū)別說明
這篇文章主要介紹了在django中form的label和verbose name的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05
Python利用pandas和matplotlib實現(xiàn)繪制堆疊柱狀圖
在數據可視化中,堆疊柱狀圖是一種常用的圖表類型,它能夠清晰地展示多個類別的數據,本文將演示如何使用 Python 的 pandas 和 matplotlib 庫繪制優(yōu)化的堆疊柱狀圖,需要的可以參考下2023-11-11

