迭代器:python
是一個抽象的概念,任何對象,若是它的類有 next 方法和 iter 方法返回本身自己,對於 string、list、dict、tuple 等這類容器對象,使用 for 循環遍歷是很方便的。在後臺 for 語句對容器對象調用 iter()函數,iter()是 python 的內置函數。iter()會返回一個定義了 next()方法的迭代器對象,它在容器中逐個訪問容器內元素,next()也是 python 的內置函數。在沒有後續元素時,next()會拋出一個 StopIteration 異常。函數
關於iter()和next():工具
一、iter(iterable)函數是把可迭代對象的迭代器取出來,內部是調用可迭代對象的__iter__方法,來取得迭代器的
二、next(iterator)函數是經過迭代器取得下一個位置的值,內部是調用迭代器對象的__next__方法,來取得下一個位置的值
注意:
當咱們已經迭代完最後一個數據以後,再次調用next()函數會拋出StopIteration的異常,來告訴咱們全部數據都已迭代完成,不用再執行next()函數了。
因此:
咱們要想構造一個迭代器,就要實現它的__next__方法。但這還不夠,python要求迭代器自己也是可迭代的,因此咱們還要爲迭代器實現__iter__方法,而__iter__方法要返回一個迭代器,迭代器自身正是一個迭代器,因此迭代器的__iter__方法返回自身便可。
結論:
一個實現了__iter__方法和__next__方法的對象,就是迭代器,迭代器同時也是一個可迭代對象spa
示例代碼:code
class FibIterator(object): """斐波那契數列迭代器""" def __init__(self, n): # 記錄生成fibonacci的數列的個數 self.n = n # 記錄當前遍歷的下標 self.current_index = 0 # 記錄fibonacci數列前面的兩個值 self.num1 = 0 self.num2 = 1 def __next__(self): """被next()函數調用來獲取下一個數""" if self.current_index < self.n: num = self.num1 self.num1, self.num2 = self.num2, self.num1 + self.num2 self.current_index += 1 return num else: raise StopIteration def __iter__(self): """迭代器的__iter__返回自身便可""" return self if __name__ == '__main__': fib = FibIterator(10) for num in fib: print(" ", num, end="")
# 運行結果: 0 1 1 2 3 5 8 13 21 34
生成器(Generator):對象
是建立迭代器的簡單而強大的工具。生成器是一種特殊的迭代器,它比迭代器寫起來更加優雅,它們寫起來就像是正規的函數,只是在須要返回數據的時候使用 yield 語句。每次 next()被調用時,生成器會返回它脫離的位置(它記憶語句最後一次執行的位置和全部的數據值)blog
最簡單的生成器就是把一個列表生成式的[ ]改爲( )
例如:g = (x*2 for x in rang(5)),就是一個生成器
另一種生成器的建立方法就是這一個函數裏面加yield:
例如把上面的斐波那契函數改寫成生成式以下:內存
def fib(n): current_index = 0 num1, num2 = 0, 1 while current_index < n: # print(num1) # 打印斐波那契數列 """ 1. 假如函數中有yield,則再也不是函數,而是生成器 2. yield 會產生一個斷點 3. 假如yield後面緊接着一個數據,就會把數據返回, 做爲next()函數或者for ...in...迭代出的下一個值 """ yield num1 num1, num2 = num2, num1 + num2 current_index += 1 if __name__ == '__main__': # 假如函數中有yield,則再也不是函數,而是一個生成器 gen = fib(10) # 生成器是一種特殊的迭代器 for num in gen: print(num)
# 運行結果: 0 1 1 2 3 5 8 13 21 34
經過代碼能夠很直觀看出生成器更優雅更省代碼ci
yield其實就是保存當前程序執行狀態。你用 for 循環的時候,每次取一個元素的時候就會計算一次。用 yield 的函數叫 generator,和 iterator 同樣,它的好處是不用一次計算全部元素,而是用一次算一次,能夠節省不少空間。generator每次計算須要上一次計算結果,因此用 yield,不然一 return,上次計算結果就沒了,簡單來講一個函數裏面加了yield就是生成器。
還有咱們除了可使用next()函數來喚醒生成器繼續執行外,還可使用send()函數來喚醒執行。使用send()函數的一個好處是能夠在喚醒的同時向斷點處傳入一個附加數據。generator
總結:
一、使用了yield關鍵字的函數再也不是函數,而是生成器。(使用了yield的函數就是生成器)
二、yield關鍵字有兩點做用:
保存當前運行狀態(斷點),而後暫停執行,即將生成器(函數)掛起
將yield關鍵字後面表達式的值做爲返回值返回,此時能夠理解爲起到了return的做用
三、可使用next()函數讓生成器從斷點處繼續執行,即喚醒生成器(函數)
區別:
生成器能作到迭代器能作的全部事,並且由於自動建立了 iter()和 next()方法,生成器顯得特別簡潔,並且生成器也是高效的,使用生成器表達式取代列表解析能夠同時節省內存。除了建立和保存程序狀態的自動方法,當發生器終結時,還會自動拋出 StopIteration 異常。