迭代器(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
可以看出生成器表達式創建了一個生成器,而且生有個特點就是惰性計算
, 只有在被檢索時候,纔會被賦值。
小結
概括
主要介紹了大概這樣幾點:
-
迭代器協議
-
自定義可迭代對象與迭代器分離,保證數據複用
-
-
生成器: 特殊的迭代器,內部實現了迭代器協議