迭代器與生成器

迭代器(iterator)

iterator: 迭代器對象,也屬於python的名詞,只能迭代一次。需要滿足如下的迭代器協議

  • 定義了__iter__方法,但是必須返回自身

  • 定義了next方法,在python3.x是__next__用來返回下一個值,並且當沒有數據了,拋出StopIteration

  • 可以保持當前的狀態

自定義iterator 與數據分離

說到這裏,迭代器對象基本出來了。下面大致說一下,如何讓自定義的類的對象成爲迭代器對象,其實就是定義__iter__next方法:

In [1]: %paste
class DataIter(object):

    def __init__(self, *args):
        self.data = list(args)
        self.ind = 0

    def __iter__(self): #返回自身
        return self

    def next(self): # 返回數據
        if self.ind == len(self.data):
            raise StopIteration
        else:
            data = self.data[self.ind]
            self.ind += 1
            return data
## -- End pasted text --

In [9]: d  = DataIter(1,2)

In [10]: for x in d: # 開始迭代
   ....:     print x
   ....:
1
2

In [13]: d.next() # 只能迭代一次,再次使用則會拋異常
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
----> 1 d.next()
<ipython-input-1-c44abc1904d8> in next(self)
     10     def next(self):
     11         if self.ind == len(self.data):
---> 12             raise StopIteration
     13         else:
     14             data = self.data[self.ind]

next函數中只能向前取數據,一次取一個可以看出來,不過不能重複取數據


生成器(generator)

首先需要明確的就是生成器也是iterator迭代器,因爲它遵循了迭代器協議.

兩種創建方式

包含yield的函數

生成器函數跟普通函數只有一點不一樣,就是把 return 換成yield,其中yield是一個語法糖,內部實現了迭代器協議,同時保持狀態可以掛起。如下:
記住一點,yield是數據的生產者,而諸如for等是數據的消費者。

def gen():
    print 'begin: generator'
    i = 0
    while True:
        print 'before return ', i
        yield i
        i += 1
        print 'after return ', i

a  = gen()

In [10]: a #只是返回一個對象
Out[10]: <generator object gen at 0x7f40c33adfa0>

In [11]: a.next() #開始執行
begin: generator
before return  0
Out[11]: 0

In [12]: a.next()
after return  1
before return  1
Out[12]: 1

首先看到while True 不必驚慌,它只會一個一個的執行~
看結果可以看出一點東西:

  • 調用gen()並沒有真實執行函數,而是隻是返回了一個生成器對象

  • 執行第一次a.next()時,才真正執行函數,執行到yield一個返回值,然後就會掛起,保持當前的名字空間等狀態。然後等待下一次的調用,從yield的下一行繼續執行。

還有一種情況也會執行生成器函數,就是當檢索生成器的元素時,如list(generator), 說白了就是當需要數據的時候,纔會執行。

In [15]: def func():
   ....:     print 'begin'
   ....:     for i in range(4):
   ....:         yield i

In [16]: a = func()

In [17]: list(a) #檢索數據,開始執行
begin
Out[17]: [0, 1, 2, 3]

yield還有其他高級應用,後面再慢慢學習。

生成器表達式

列表生成器十分方便:如下,求10以內的奇數:
[i for i in range(10) if i % 2]

同樣在python 2.4也引入了生成器表達式,而且形式非常類似,就是把[]換成了().

In [18]: a = ( i for i in range(4))

In [19]: a
Out[19]: <generator object <genexpr> at 0x7f40c2cfe410>

In [20]: a.next()
Out[20]: 0

可以看出生成器表達式創建了一個生成器,而且生有個特點就是惰性計算, 只有在被檢索時候,纔會被賦值。


小結

概括

主要介紹了大概這樣幾點:

  • 迭代器協議

    • 自定義可迭代對象與迭代器分離,保證數據複用

  • 生成器: 特殊的迭代器,內部實現了迭代器協議





發佈了36 篇原創文章 · 獲贊 14 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章