這一節來學習生成器(generator)和迭代器(iterator)
首先來回憶一個例子,這裏打印rest的時候爲什麼要通過list(rest)打出,而不是直接輸出rest?
>>> li=[11,22,33] rest=filter(lambda x:x>22,li) print(list(rest)) -------- [33]
試試看,如果直接輸出是什麼結果?
>>> li=[11,22,33] rest=filter(lambda x:x>22,li) print(rest) <filter object at 0x00000192C88AF4A8>
事實上,如果在2.7裏面,他會直接輸出結果,但是在3.X以後,他只會返回一個具有生成能力的對象,而不是直接輸出所有結果,這樣的好處是如果我們有成千上萬個數據要輸出,他不會直接一股腦的就輸出來了。我們需要循環地輸出這個對象生成所有需要的值。比如把上面的例子改成for循環也是一樣的
>>> li=[11,22,33] rest=filter(lambda x:x>22,li) for i in rest: print(i) 33
現在來看看基本的定義:
1.迭代器是訪問集合元素的一種方式。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退,不過這也沒什麼,因爲人們很少在迭代途中往後退。另外,迭代器的一大優點是不要求事先準備好整個迭代過程中所有的元素。迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之後,元素可以不存在或者被銷燬。這個特點使得它特別適合用於遍歷一些巨大的或是無限的集合,比如幾個G的文件
特點:
訪問者不需要關心迭代器內部的結構,僅需通過next()方法不斷去取下一個內容
不能隨機訪問集合中的某個值 ,只能從頭到尾依次訪問
訪問到一半時不能往回退
便於循環比較大的數據集合,節省內存
2. 一個函數調用時返回一個迭代器,那這個函數就叫做生成器(generator);如果函數中包含yield語法,那這個函數就會變成生成器;
下面直接通過例子說明:
比如我定義了一個函數f1,裏面包含了yield這個關鍵字,那麼他就變成了一個生成器,他的結果只能通過迭代器的next方法一步步輸出
>>> def f1(): print("1") yield 22 print("2") yield 33 print("3") yield 44 r=f1() print(r,type(r)) print(r.__next__()) print(r.__next__()) print(r.__next__()) -------------------- <generator object f1 at 0x00000192C88DC728> <class 'generator'> 1 22 2 33 3
當然通過循環語句自動調用迭代器更方便了
for item in r: print(item)
例2 通過生成器做一個range的函數
>>> def nrange(num): temp = -1 while True: temp = temp + 1 if temp >= num: return else: yield temp r=nrange(5) print(r) for item in r: print(item) --------------------- <generator object nrange at 0x00000192C88DC360> 0 1 2 3 4
再看個例子
def split_line(): print ('ready to split') result="4 5 6" while True: line=yield result result=line.split() s=split_line() s.__next__() #send的值去替換掉line的值,返回值是result ret=s.send('1 2 3') print(ret) ret=s.send('a b c') print(ret) "C:\Program Files\Python3\python.exe" C:/Users/yli/pycharmprojects/Exercise/Week12/test.py ready to split ---------- ['1', '2', '3'] ['a', 'b', 'c']