在學習生成器以前,首先咱們要知道什麼是生成器? 在python中一邊循環一邊計算的機制就是生成器(generator)。python
知道了什麼是生成器以後,咱們須要知道爲何要有生成器呢? 也就是說這種一邊循環一邊計算的機制有什麼用處呢?算法
咱們知道列表中全部的數據都存在內存中,若是數據不少的話將會特別消耗內存。先不說內存有沒有這麼大,假設咱們僅僅須要訪問前面幾個元素,那後面元素所佔用的空間豈不是都白費了嗎。函數
因此這個時候若是列表中的元素可以按照某種算法自動推算出來呢,是否是就沒必要建立完整的列表,能夠節省大量的內存空間了。因此若是又想節省內存,又須要用到不少數據就能夠使用生成器。學習
建立生成器有好幾種方法,最簡單一種就是把一個列表生成式的[]
改爲()
,這樣就能直接建立一個生成器:code
# 列表生成式 list = [x for x in range(10)] print(list) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 生成器 generator = (x for x in range(10)) print(generator) # <generator object <genexpr> at 0x0000000002131A20>
咱們能夠直接經過print(list),將list中全部元素打印出來。可是print(generator)打印出來的倒是一個對象,若是咱們想要打印出生成器中的元素要怎麼幫?有兩種方式:對象
generator = (x for x in range(10)) print(next(generator)) # 0 print(next(generator)) # 1 print(next(generator)) # 2
每次調用一次next()方法
就計算出下一個元素的值,直到超出最後一個元素時,則會拋出StopIteration錯誤。 這種方法只能一個一個元素打印,若是隻須要前面幾個元素,用這樣方法恰好。若是須要打印不少元素,這個方法就太不方便了。這時候咱們能夠用第二種方法。blog
generator = (x for x in range(5)) for g in generator: print(g) # 輸出: 0 1 2 3 4
這樣不只能夠一次性將全部元素打印出來,且經過for循環打印不須要擔憂會發生StopIteration異常。內存
這樣看起來和列表生成式沒差?但咱們要注意列表生成式是直接將全部元素存在了內存空間中,這樣佔用了大量內存。而生成器並非當即將結果寫入內存, 而是保存的一種計算方式, 經過不斷的計算, 能夠獲取到相應的位置的值,因此佔用的內存僅僅是對計算對象的保存。get
若是推算的算法比較複雜,用相似列表生成式的for循環沒法實現的時候,還能夠用函數來實現。只須要在函數中定義一個yield語句就行。 因此帶有 yield 的函數再也不是一個普通函數,而是一個生成器。yield至關於 return 返回一個值,而且記住這個返回的位置,下次迭代時,代碼從yield的下一條語句開始執行。generator
def gen_yield(): for i in range(3): yield i g = gen_yield() print(next(g)) # 0 print(next(g)) # 1 print(next(g)) # 2 print(next(g)) # 報錯:StopIteration # 生成器函數每一次next()迭代,會返回當前yield的值,且在此處暫停,下一次next()迭代, # 從上一次的yield處開始,向下執行,且依然在下一次的yield中暫停 # for循環迭代 for i in g: print(i) # 輸出: 0 1 2
上述中gen_yield()
其實就是一個生成器函數,若是咱們想要獲得這個函數中的返回值,一樣能夠經過next()方法或者for循環迭代來獲得。