17-Python與設計模式--迭代器模式
一、迭代器與生成器
今天的主角是迭代器模式。在python中,迭代器並不用舉太多的例子,因為python中的迭代器應用實在太多了(不管是python還是其它很多的程式語言中,實際上迭代器都已經納入到了常用的庫或者包中)。而且在當前,也幾乎沒有人專門去開發一個迭代器,而是直接去使用list、string、set、dict等python可迭代物件,或者直接使用__iter__和next函式來實現迭代器。如下例:
if __name__=="__main__": lst=["hello Alice","hello Bob","hello Eve"] lst_iter=iter(lst) print lst_iter print lst_iter.next() print lst_iter.next() print lst_iter.next() print lst_iter.next()
列印如下:
hello Alice
hello Bob
hello Eve
Traceback (most recent call last):
File "D:/WorkSpace/Project/PyDesignMode/example.py", line 719, in
print lst_iter.next()
StopIteration
在這種迭代器的使用過程中,如果next超過了迭代範圍,會丟擲異常。
在python物件的方法中,也可以輕易使用迭代器模式構造可迭代物件,如下例:
class MyIter(object): def __init__(self, n): self.index = 0 self.n = n def __iter__(self): return self def next(self): if self.index < self.n: value = self.index**2 self.index += 1 return value else: raise StopIteration()
__iter__和next實現了迭代器最基本的方法。如下方式進行呼叫:
if __name__=="__main__": x_square=MyIter(10) for x in x_square: print x
列印如下:
0
1
4
9
16
25
36
49
64
81
注意__iter__方法中的返回值,由於直接返回了self,因而該迭代器是無法重複迭代的,如以下業務場景:
if __name__=="__main__": x_square=MyIter(10) for x in x_square: print x for x in x_square: print x
只能列印一遍平方值。解決辦法是,在__iter__中不返回例項,而再返回一個物件,寫成:
def __iter__(self): return MyIter(self.n)
這樣,在每次迭代時都可以將迭代器“初始化”,就可以多次迭代了。
另外,在python中,使用生成器可以很方便的支援迭代器協議。生成器通過生成器函式產生,生成器函式可以通過常規的def語句來定義,但是不用return返回,而是用yield一次返回一個結果,在每個結果之間掛起和繼續它們的狀態,來自動實現迭代協議。
如下例:
def MyGenerater(n): index=0 while index<n: yield index**2 index+=1
注意,這是個函式。在每次呼叫生成器,得到返回結果後,現場得以保留,下次再呼叫該生 成器時,返回保留的現場從yield後繼續執行程式。
if __name__=="__main__": x_square=MyGenerater(10) for x in x_square: print x
列印結果與上面一致。
二、迭代器模式
迭代器模式的定義如下:它提供一種方法,訪問一個容器物件中各個元素,而又不需要暴露物件的內部細節。