Iterator(迭代器)
-
概念
迭代器是訪問集合元素的一種方式。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會后退。
-
可迭代對象
迭代器提供了一個統一的訪問集合的接口。只要是實現了iter()或getitem()方法的對象,就可以使用迭代器進行訪問。
例子:
- 序列:字符串、列表、元組
- 非序列:字典、文件
- 自定義類:用戶自定義的類實現了iter()或getitem()方法的對象
-
可迭代對象創建的兩種方法
第一種:
# 迭代器對象實現了__iter__()方法 class Fibs: def __init__(self): self.a = 0 self.b = 0 def next(self): self.a,self.b = self.b,self.a+self.b return self.a def __iter__(self): return self
__iter__
()方法實現了對象可迭代,next()方法實現了迭代。第二種:
# 用iter()工廠類實例化一個可迭代對象 it = iter([1,2,3]) it.next()
-
從迭代器中獲得序列
it = iter([1,23,3]) lits(it)
使用list構造方法顯式地講迭代器轉化成列表。
-
一種更方便的建立迭代器
# 用括號擴住才是迭代器 it = (x for x in [2,3,4])
生成器
概念
生成器是一種用普通的函數語法定義的迭代器(也叫簡單生成器),有點像java中的靜態域里面的數據,但用更加靈活。生成器不會把結果保存在一個系列中,而是保存生成器的狀態,在每次進行迭代時返回一個值,直到遇到StopIteration異常結束。-
yield
在函數中如果出現了yield關鍵字,那么該函數就不再是普通函數,而是生成器函數。
yield 的作用就是把一個函數變成一個 generator,帶有 yield 的函數不再是一個普通函數,Python 解釋器會將其視為一個 generator。可以用for循環遍歷相比于迭代器,生成器更加靈活。
程序執行到yield后就會返回輸出,yield下面的代碼會在下次調用next()時運行
-
yield與return
在一個生成器中,如果沒有return,則默認執行到函數完畢時返回StopIteration
如果遇到return,如果在執行過程中 return,則直接拋出 StopIteration 終止迭代。# 不會執行到'b' def ge(): yield 'a' return yield 'b'
如果在return后返回一個值,那么這個值為StopIteration異常的說明,不是程序的返回值。
# 不會輸出'world' def ge(): yield 'hello' return 'world'
?
-
創建一個生成器
-
簡單生成器
# 簡單生成器,一個無窮產生奇數的生成器函數 def odd(): n=1 while True: yield n n+=2
-
循環生成器
# 循環生成器 g = ((i+2)**2 for i in range(2, 27))
range()是一個生成器
遞歸生成器
# 處理多層嵌套的數據(二維數組等等) def flatten(nested): try: for sublist in nested: forelement in flatten(sublist): yield element except TypeError: yield nested list(flatten([1,[2,3],[4,[5,6]],7,8]))
當函數被告知展開一個元素(元素無法展開,一個可迭代對象才能展開 ),for循環會引發一個TypeError異常。但上面的那種情況在處理元素是字符串的時候不適用。
def flatten(nested): try: # 不要迭代類似字符串的數據對象 try: nested + '' # 當nested不是一個字符串的時候會引發一個TypeError except TypeError: pass else: raise TypeError for sublist in nested: for element in flatten(sublist): yield element except TypeError: yield nested # 下面的是可以打印出多層嵌套的數據(無論是一般數據還是字符串) def flatten(nested): try: if isinstance(nested, str): raise TypeError for sublist in nested: for element in sublist: yield element except TypeError: yield nested
?
-
生成器方法
-
send
可以改變生成器內部值的方法
要在生成器掛起后才有意義(也就是說在yield函數第一次被運行之后),如果相對剛剛啟動的生成器使用send()方法,可以講None作為其參數進行調用。
def repeater(value): while True: new = (yield value) if new is not None: value = new # 使用方法 r = repeater(42) r.next() r.send('Hello world!')
-
throw
用于在生成器內引發一個異常(在yield表達式中)
def gen(): while True: try: yield 'normal value' yield 'normal value 2' print 'here' except ValueError: print 'we got ValueError here' except TypeError: break # gen()用法 g - gen() print next(g) print g.throw(Valueerror) print next(g) print g.throw(TypeError) """ 程序的輸出: print(next(g)):會輸出normal value,并停留在yield ‘normal value 2’之前。 由于執行了g.throw(ValueError),所以會跳過所有后續的try語句,也就是說yield ‘normal value 2’不會被執行,然后進入到except語句,打印出we got ValueError here。然后再次進入到while語句部分,消耗一個yield,所以會輸出normal value。 print(next(g)),會執行yield ‘normal value 2’語句,并停留在執行完該語句后的位置。 g.throw(TypeError):會跳出try語句,從而print(‘here’)不會被執行,然后執行break語句,跳出while循環,然后到達程序結尾,所以跑出StopIteration異常。 """
-
close
它在yield運行處引發一個GeneratorExit異常,可以對生成器內進行代碼清理,一般講yield語句放在try/finally語句中。執行close()方法后,生成器對象就會被銷毀,不能再調用next()方法
def gen(): yield 1 yield 2 yield 3 g = gen() print next(g) g.close() next(g)
?
-
-