彻底理解 Python 生成器
原文鏈接:https://www.cnblogs.com/liangmingshen/p/9706181.html
?
1. 生成器定義
在Python中,一邊循環(huán)一邊計算的機制,稱為生成器:generator。
?
2. 為什么要有生成器
列表所有數(shù)據(jù)都在內(nèi)存中,如果有海量數(shù)據(jù)的話將會非常耗內(nèi)存。
如:僅僅需要訪問前面幾個元素,那后面絕大多數(shù)元素占用的空間都白白浪費了。
如果列表元素按照某種算法推算出來,那我們就可以在循環(huán)的過程中不斷推算出后續(xù)的元素,這樣就不必創(chuàng)建完整的list,從而節(jié)省大量的空間。
簡單一句話:我又想要得到龐大的數(shù)據(jù),又想讓它占用空間少,那就用生成器!
?
3.如何創(chuàng)建生成器
第一種方法很簡單,只要把一個列表生成式的[]改成(),就創(chuàng)建了一個generator:
>>> L = [x * x for x in range(10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x * x for x in range(10)) >>> g <generator object <genexpr> at 0x1022ef630>創(chuàng)建L和g的區(qū)別僅在于最外層的[]和(),L是一個list,而g是一個generator。
方法二,?如果一個函數(shù)中包含yield關(guān)鍵字,那么這個函數(shù)就不再是一個普通函數(shù),而是一個generator。調(diào)用函數(shù)就是創(chuàng)建了一個生成器(generator)對象。
?
4. 生成器的工作原理
(1)生成器(generator)能夠迭代的關(guān)鍵是它有一個next()方法,
工作原理就是通過重復(fù)調(diào)用next()方法,直到捕獲一個異常。
(2)帶有 yield 的函數(shù)不再是一個普通函數(shù),而是一個生成器generator。
可用next()調(diào)用生成器對象來取值。next 兩種方式 t.__next__()? |? next(t)。
可用for 循環(huán)獲取返回值(每執(zhí)行一次,取生成器里面一個值)
(基本上不會用next()來獲取下一個返回值,而是直接使用for循環(huán)來迭代)。
(3)yield相當(dāng)于 return 返回一個值,并且記住這個返回的位置,下次迭代時,代碼從yield的下一條語句開始執(zhí)行。
(4).send() 和next()一樣,都能讓生成器繼續(xù)往下走一步(下次遇到y(tǒng)ield停),但send()能傳一個值,這個值作為yield表達(dá)式整體的結(jié)果
——換句話說,就是send可以強行修改上一個yield表達(dá)式值。比如函數(shù)中有一個yield賦值,a = yield 5,第一次迭代到這里會返回5,a還沒有賦值。第二次迭代時,使用.send(10),那么,就是強行修改yield 5表達(dá)式的值為10,本來是5的,那么a=10
?
感受下yield返回值的過程(關(guān)注點:每次停在哪,下次又開始在哪)及send()傳參的通訊過程,
思考None是如何產(chǎn)生的(第一次取值:yield 返回了 i 值 0,停在yield i,temp沒賦到值。第二次取值,開始在print,temp沒被賦值,故打印None,i加1,繼續(xù)while判斷,yield? 返回了 i 值 1,停在yield i):
好了,話不多說,翠花,上栗子:
#encoding:UTF-8 def yield_test(n): for i in range(n): yield call(i) print("i=",i) print("Done.") def call(i): return i*2 for i in yield_test(5): print(i,",")結(jié)果:
>>> , i= 0 , i= 1 , i= 2 , i= 3 , i= 4 Done. >>>理解的關(guān)鍵在于:下次迭代時,代碼從yield的下一條語句開始執(zhí)行。
?
?總結(jié):
什么是生成器?
生成器僅僅保存了一套生成數(shù)值的算法,并且沒有讓這個算法現(xiàn)在就開始執(zhí)行,而是我什么時候調(diào)它,它什么時候開始計算一個新的值,并給你返回。
?
練習(xí)題:
def count_down(n):while n >= 0:newn = yield nprint('newn', newn)if newn:print('if')n = newnprint('n =', n)else:n -= 1cd = count_down(5) for i in cd:print(i, ',')if i == 5:cd.send(3)結(jié)果:
總結(jié)
以上是生活随笔為你收集整理的彻底理解 Python 生成器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python3爬虫(5)百度云盘暴力破解
- 下一篇: python3之协程(1)---协程简介