Python生成器和迭代器

1、什麼是生成器

要說生成器,那就要先看列表,有了列表為啥還要生產器呢。列表可以寫成解析式,書寫簡單,運行速度快,但是列表是一次性生成全部數據,如果數據較大就需要很大的記憶體。

>>> a=[i*i for i in range(10)]  >> a  [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

列表a需要一次把全部數據生成出來,如果數據成千上萬就會受限制。

如果列表元素不是一次性全部生成,而是在循環中不斷的計算推導出來,那就不需要一次創建列表數組,不需要申請很大的記憶體空間,這就是生成器。

2、生成器的特點

上面的列表推導式的方括弧改為圓括弧,就是生成器。

>>> a=(i*i for i in range(10))  >>> a  <generator object <genexpr> at 0x00000224FFB4DB48>

那麼怎麼從生成器里取數據呢?

>>> next(a)  0  >>> next(a)  1  >>> next(a)  4  >>> next(a)  9  >>> next(a)  16  >>> next(a)  25

生成器generator有一個next方法,每次調用都會計算出他的下一個元素的值。生成器是可以迭代的,所以可以直接使用for語句循環生成器。

>>> a=[i*i for i in range(10)]  >>> for i in a:      print(i, end=' ')  >>> 0 1 4 9 16 25 36 49 64 81

除了使用圓括弧創建生成器,也可以用yeild創建生成器,含有yeild關鍵字的函數都是生成器。生成器其實是一種特殊的迭代器,但是不需要像迭代器一樣實現__iter__和__next__方法,只需要使用關鍵字yield就可以。

def gen_squares(num):      for x in range(num):          print("x0=",x)          yield x ** 2          print("x1=",x)

調用生成器:

for i in gen_squares(5):      print(i)

輸出如下,開始x=0,先輸出x0=0,然後yeild返回print(i)列印平方數。下次循環回到yeild位置執行輸出x1=1,然後循環x=1,輸出x0=1,再次yeild到print(i)。

x0= 0  0  x1= 0  x0= 1  1  x1= 1  x0= 2  4  x1= 2  x0= 3  9  x1= 3  x0= 4  16  x1= 4

調用部分做個簡單修改:

for i in gen_squares(5):      print(i)      if i==1:          break

輸出為如下,可見yield能保存內部狀態,並掛起中斷退出。在下一輪迭代調用時,從yield的地方繼續執行,並且沿用上一輪的函數內部變數的狀態,直到內部循環過程結束。

x0= 0  0  x1= 0  x0= 1  1

python使用生成器對延遲操作提供了支援,需要時才計算,不提前計算,這種做法節約記憶體空間,但是需要一直調用計算過程,可以說是時間換空間吧。

3、什麼是迭代器

實現了__iter__和__next__方法的對象都稱為迭代器。迭代器完成迭代功能,基於上一次的結果重複計算,自動記錄所在的位置,而不需要手動記錄索引,含有__iter__方法的對象都是可迭代對象。

迭代對象內置兩個方法:__next__和__iter__方法。next方法可以使迭代器自動記錄迭代位置而不需要用戶維護索引。iter方法能返回迭代器本身。

迭代器是一個有狀態的對象,在調用next() 的時候返回下一個值,如果容器中沒有更多元素了,則拋出StopIteration異常。

列表、元組就實現了迭代器。

>>> a=[1,2,3,4]  >>> it = a.__iter__()  >>> next(it)  1  >>> next(it)  2  >>> next(it)  3  >>> next(it)  4  >>> next(it)  Traceback (most recent call last):    File "<pyshell#547>", line 1, in <module>      next(it)  StopIteration

4、實現迭代對象

class square:      def __init__(self, n):          self.prev = 0          self.curr = 0          self.n = n        def __iter__(self):          return self        def __next__(self):          if(self.curr < self.n):              self.prv = self.curr * self.curr              self.curr+=1              return self.prv          else:               raise StopIteration  
a
= square(10) for i in a: print(i) print("rn-------rn") b = square(5) for i in b: print(i)

輸出結果為:

==================== RESTART: C:/Users/plu/my_python/t1.py ====================  0  1  4  9  16  25  36  49  64  81    -------    0  1  4  9  16  >>>