首頁  >  文章  >  後端開發  >  Python中的生成器是如何運作的?

Python中的生成器是如何運作的?

WBOY
WBOY轉載
2023-04-24 19:46:051050瀏覽

什麼是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__ == &#39;__main__&#39;:
    main()

粗看程式碼,可能會覺著這個是個啥啊,為啥不直接用range來生成,偏偏要用yield,哎,不急,我們接著往下看為什麼需要生成器,或者說,生成器解決了什麼問題。

為什麼需要python生成器

在說明這個問題之前,我們先來寫一個需求,輸出 0——10000000 以內的數據,而後運行查看導出內存運行截圖。

呼叫python程式記憶體資訊輔助說明

這裡可以藉助pythonmemory_profiler模組來偵測程式記憶體的佔用情況。

安裝memory_profiler庫:

pip3 install memory_profiler

使用方法很簡單,在需要偵測的函數或程式碼前加上@profile裝飾器即可,例如:

@profile
def main():
    pass

生成.dat檔案

mprof run

##匯出圖示,可以使用

mprof plot --output=filename

python案例代碼

以下2個程序,都是輸出0—9999999之間的數據,不同的是,第一個程式是使用

range而後給append進位list中,第二個則是使用迭代器來產生該資料。

main.py程式

@profile
def main():
    data = list(range(10000000))
    for i in data:
        pass

if __name__ == &#39;__main__&#39;:
    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__ == &#39;__main__&#39;:
    main()

執行程式

程式碼也有了,就可以按照上述來運行一下程序,並且導出內存信息

Python中的生成器是如何運作的?

運行後內存信息查看

main.py運行記憶體圖

Python中的生成器是如何運作的?

main_2.py 運行記憶體圖

Python中的生成器是如何運作的?

如上2張比較圖,當我們將資料疊加進列表,再輸出的時候,佔用記憶體接近400M,而使用迭代器來計算下一個值記憶體只使用16M。

透過上述案例,我們應該知道為什麼要使用生成器了吧。

python生成器原理

由於生成器表達式

yield語句涉及到了python解釋權內部機制,所以很難查看其原始碼,很難取得其原理,不過我們可以利用yield的暫停機制,來探尋一下生成器。

可以寫如下程式碼:

def testGenerator():
    print("进入生成器")
    yield "pdudo"
    print("第一次输出")
    yield "juejin"
    print("第二次输出")

def main():
    xx = testGenerator()
    print(next(xx))
    print(next(xx))

if __name__ == &#39;__main__&#39;:
    main()

運行後效果如下

Python中的生成器是如何運作的?

透過上述實例,再結合下面這段生成器的運行過程,會加深對生成器的感觸。

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__ == &#39;__main__&#39;:
    main()

其中,程式碼

(i for i in [1,2,3,4,5])就等同於printNums函數,其型別都是生成器,我們可以使用type列印出來看下。

改下程式碼,輸出結果如下:

Python中的生成器是如何運作的?

以上是Python中的生成器是如何運作的?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除