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