注意:
1.構建可迭代對象和迭代器時經常會出現錯誤,原因是混淆了二者。
(1)可迭代對象有個__iter__( ) 方法,調用該方法每次都實例化一個新的迭代器。
(2)迭代器要實現__next__( )方法返回單個元素,還要實現__iter__( )方法返回本身(self)
因此,迭代器可以迭代,但是可迭代對象不是迭代器!!!
導入模塊:from collections.abc import Iterable,Iterator
可以用 isinstance( x , Iterable ) 判斷x是否爲可迭代對象;
可以用 isinstance( x , Iterator ) 判斷x是否爲迭代器;
2.生成器是特殊的迭代器
一、可迭代對象 iterable
一句話:“實現了__iter__方法的對象就叫做可迭代對象”
簡單點來說能用for循環進行迭代的對象就是可迭代對象。比如:字符串、列表、元組、集合...
注意:
1.調用可迭代對象的__iter__() 方法返回一個可迭代對象(iterable)
2.不斷調用迭代器的__next__() 方法返回元素
3.直到迭代完成後,處理StopIteration異常
>>> a = [1,2,3] >>> b = a.__iter__() >>> print(b) <list_iterator object at 0x000001E9C5781860> >>> b.__next__() 1 >>> b.__next__() 2 >>> b.__next__() 3 >>> b.__next__() Traceback (most recent call last): File "<pyshell#6>", line 1, in <module> b.__next__() StopIteration
二、迭代器 iterator
什麼叫迭代器?它就是一個帶狀態的對象,他能在你調用
next()
方法的時候返回容器中的下一個值。任何實現了
__iter__
和__next__()
方法的對象都是迭代器。標準的迭代器接口有兩個方法:
(1)__next__( ) :返回下一個可用的元素,如果沒有元素,拋出StopIteration異常。
(2)__iter__( ) :返回self,以便在應該使用可迭代對象的地方使用迭代器,比如for循環中。
迭代器就像一個懶加載的工廠,等到有人需要的時候纔給它生成值返回,沒調用的時候就處於休眠狀態等待下一次調用。直到無元素可調用,返回StopIteration異常。
例子如下實現斐波那契數列:
>>> class Fib(): def __init__(self,max): self.n = 0 self.prev = 0 self.curr = 1 self.max = max def __iter__(self): return self def __next__(self): if self.n<self.max: value = self.curr self.curr += self.prev self.prev = value self.n += 1 return value else: raise StopIteration >>> f = Fib(5) >>> next(f) 1 >>> f.__next__() 1 >>> next(f) 2 >>> next(f) 3 >>> next(f) 5 >>> next(f) Traceback (most recent call last): File "<pyshell#32>", line 1, in <module> next(f) File "<pyshell#25>", line 17, in __next__ raise StopIteration StopIteration
三、生成器 generator
注意:生成器是特殊的迭代器(反之不成立),不需要寫__iter__( )、__next__( ),只需要一個yield關鍵字。
在Python中,這種一邊循環一邊計算的機制,稱爲生成器:generator
使用next()函數和send()函數恢復生成器
(1)next()函數:next的作用是喚醒並繼續執行
(2)send()函數:send的作用是喚醒並繼續執行,發送一個信息到生成器內部
生成器類似於返回值爲數組的一個函數,這個函數可以接受參數,可以被調用,但是,不同於一般的函數會一次性返回包括了所有數值的數組,生成器一次只能產生一個值,這樣消耗的內存數量將大大減小,而且允許調用函數可以很快的處理前幾個返回值,因此生成器看起來像是一個函數,但是表現得卻像是迭代器.
python提供了兩種基本的方式:
(1)生成器函數:用def 定義的利用關鍵字yield一次性返回一個結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次從它離開的地方繼續執行。如下:
# 例子1:斐波那契數列 def Fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return '啊哈沒有數據了喔' f = Fib(10) # 使用一個循環捕獲最後return 返回的值,保存在異常StopIteration的value中 while 1: try: x = next(f) print('f:', x) except StopIteration as e: print('生成器最後返回的值:', e.value) break # 例子2: def foo(): print("first") count=yield print(count) yield f = foo() f.send(None) f.send(2) """ 例子2解釋: f = foo() 返回一個生成器 f.send(None) 進行函數執行代碼,遇到count = yield,凍結並跳出函數體 f.send(2) 再次進入函數體,接着凍結的代碼繼續執行,把2傳給變量count, 打印count,遇到yield凍結並跳出函數 """
(2)生成器表達式:生成器表達式是列表推導式的生成器版本,看起來像列表推導式,但是它返回的是一個生成器對象而不是列表對象。
from collections.abc import Iterable,Iterator a = (x for x in range(10)) print(isinstance(a,Iterable)) # True print(isinstance(a,Iterator)) # True