本文小編為大家詳細介紹“Python生成器是怎么工作的”,內(nèi)容詳細,步驟清晰,細節(jié)處理妥當,希望這篇“Python生成器是怎么工作的”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
10年積累的成都做網(wǎng)站、成都網(wǎng)站建設(shè)經(jīng)驗,可以快速應對客戶對網(wǎng)站的新想法和需求。提供各種問題對應的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認識你,你也不認識我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有察哈爾右翼前免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
生成器是一種特殊的迭代器,它內(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ù),而后運行查看導出內(nèi)存運行截圖。
這里可以借助python
的memory_profiler
模塊來檢測程序內(nèi)存的占用情況。
安裝memory_profiler
庫:
pip3 install memory_profiler
使用方法很簡單,在需要檢測的函數(shù)或者是代碼前添加@profile
裝飾器即可,例如:
@profile def main(): pass
生成.dat
文件
mprof run
導出圖示,可以使用
mprof plot --output=filename
以下2個程序,都是輸出0—9999999之間的數(shù)據(jù),不同的是,第一個程序是使用range
而后給append
進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()
代碼也有了,就可以按照上述來運行一下程序,并且導出內(nèi)存信息
main.py
運行內(nèi)存圖
main_2.py
運行內(nèi)存圖
如上2張對比圖,當我們將數(shù)據(jù)疊加進列表,再輸出的時候,占用內(nèi)存接近400M,而使用迭代器來計算下一個值內(nèi)存僅使用16M。
通過上述案例,我們應該知道為什么要使用生成器了吧。
由于生成器表達式yield
語句涉及到了python
解釋權(quán)內(nèi)部機制,所以很難查看其源碼,很難獲取其原理,不過我們可以利用yield
的暫停機制,來探尋一下生成器。
可以編寫如下代碼:
def testGenerator(): print("進入生成器") yield "pdudo" print("第一次輸出") yield "juejin" print("第二次輸出") def main(): xx = testGenerator() print(next(xx)) print(next(xx)) if __name__ == '__main__': main()
運行后效果如下
通過上述實例,再結(jié)合下面這段生成器的運行過程,會加深對生成器的感觸。
當python
遇到yield
語句時,會記錄當前函數(shù)的運行狀態(tài),并且暫停執(zhí)行,將結(jié)果拋出。會持續(xù)等待下一次調(diào)用__next__
方法,該方法調(diào)用后,會恢復函數(shù)的運行,直至下一個yield
語句或者函數(shù)結(jié)束,執(zhí)行到最后沒有yield
函數(shù)可執(zhí)行的時候,會拋StopIteration
來標志生成器的結(jié)束。
在python
中,生成器除了寫在函數(shù)中,使用yield
返回之外,還可以直接使用生成器表達式,額。。。可能很抽象,但是你看下面這段代碼,你就明白了。
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)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。