您好,登錄后才能下訂單哦!
本文小編為大家詳細(xì)介紹“Python生成器是怎么工作的”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Python生成器是怎么工作的”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。
生成器是一種特殊的迭代器,它內(nèi)部也有__iter__
方法和__next__
方法,在終止生成器的時候,還是會拋StopIteration
異常以此來退出循環(huán),只不過相比于迭代器,生成器還有特性會保存“中間值”,下次運行的時候,還會借助這個“中間值”來操作。生成器的關(guān)鍵字是yield
,我們下面來寫一個最簡單的生成器。
#!/usr/bin/env python def printNums(): i = 0 while i<10: yield i i = i + 1 def main(): for i in printNums(): print(i) if __name__ == '__main__': main()
粗看代碼,可能會覺著這個是個啥啊,為啥不直接用range
來生成,偏偏要用yield
,哎,不急,我們接著往下看為什么需要生成器,或者說,生成器解決了什么問題。
在說明這個問題之前,我們先來寫一個需求,輸出 0——10000000 以內(nèi)的數(shù)據(jù),而后運行查看導(dǎo)出內(nèi)存運行截圖。
這里可以借助python
的memory_profiler
模塊來檢測程序內(nèi)存的占用情況。
安裝memory_profiler
庫:
pip3 install memory_profiler
使用方法很簡單,在需要檢測的函數(shù)或者是代碼前添加@profile
裝飾器即可,例如:
@profile def main(): pass
生成.dat
文件
mprof run <executable>
導(dǎo)出圖示,可以使用
mprof plot --output=filename
以下2個程序,都是輸出0—9999999之間的數(shù)據(jù),不同的是,第一個程序是使用range
而后給append
進(jìn)list
中,第二個則是使用迭代器來生成該數(shù)據(jù)。
main.py
程序
@profile def main(): data = list(range(10000000)) for i in data: pass if __name__ == '__main__': main()
main_2.py
程序
def printNum(): i = 0 while i < 10000000: yield i i = i + 1 @profile def main(): for i in printNum(): pass if __name__ == '__main__': main()
代碼也有了,就可以按照上述來運行一下程序,并且導(dǎo)出內(nèi)存信息
main.py
運行內(nèi)存圖
main_2.py
運行內(nèi)存圖
如上2張對比圖,當(dāng)我們將數(shù)據(jù)疊加進(jìn)列表,再輸出的時候,占用內(nèi)存接近400M,而使用迭代器來計算下一個值內(nèi)存僅使用16M。
通過上述案例,我們應(yīng)該知道為什么要使用生成器了吧。
由于生成器表達(dá)式yield
語句涉及到了python
解釋權(quán)內(nèi)部機制,所以很難查看其源碼,很難獲取其原理,不過我們可以利用yield
的暫停機制,來探尋一下生成器。
可以編寫如下代碼:
def testGenerator(): print("進(jìn)入生成器") yield "pdudo" print("第一次輸出") yield "juejin" print("第二次輸出") def main(): xx = testGenerator() print(next(xx)) print(next(xx)) if __name__ == '__main__': main()
運行后效果如下
通過上述實例,再結(jié)合下面這段生成器的運行過程,會加深對生成器的感觸。
當(dāng)python
遇到yield
語句時,會記錄當(dāng)前函數(shù)的運行狀態(tài),并且暫停執(zhí)行,將結(jié)果拋出。會持續(xù)等待下一次調(diào)用__next__
方法,該方法調(diào)用后,會恢復(fù)函數(shù)的運行,直至下一個yield
語句或者函數(shù)結(jié)束,執(zhí)行到最后沒有yield
函數(shù)可執(zhí)行的時候,會拋StopIteration
來標(biāo)志生成器的結(jié)束。
在python
中,生成器除了寫在函數(shù)中,使用yield
返回之外,還可以直接使用生成器表達(dá)式,額。。。可能很抽象,但是你看下面這段代碼,你就明白了。
def printNums(): for i in [1,2,3,4,5]: yield i def main(): for i in printNums(): print(i) gener = (i for i in [1,2,3,4,5]) for i in gener: print(i) if __name__ == '__main__': main()
其中,代碼(i for i in [1,2,3,4,5])
就等同于printNums
函數(shù),其類型都是生成器,我們可以使用type
打印出來看下。
改下代碼,輸出結(jié)果如下:
讀到這里,這篇“Python生成器是怎么工作的”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。