什麼是迭代器:python
迭代器是一個能夠記住遍歷的位置對象算法
迭代器對象從集合的第一個元素元素開始訪問,直到全部元素被訪問完結束,迭代器只能往前不會後退。編程
迭代器有兩個基本方法:iter ,next 方法併發
內置函數iter(),next() 本質上都是用的對象.__iter__(),__next__()的方法ide
內置函數 iter(iterable),表示把可迭代對象 變成迭代器(iterator)函數
內置函數next(iterator) ,表示查看下一次迭代的值(固然也能夠用 iterator.__next__() ,查看下一次迭代的值)工具
1.迭代器(iterator)協議是指:對象必須提供一共next方法,執行該方法妖魔返回迭代中的下一項,要麼就引發一個Stopiteration異常,已終止迭代。spa
2.可迭代對象:實現了迭代器協議的對象,(該對象內部定義了一個__iter__()的方法 例:str.__iter__())就是可迭代對象線程
3.協議是一種約定,可迭代對象實現了迭代器協議,python的內部工具(如。for循環,sum,min,max函數等)使用迭代器協議訪問對象3d
for循環本質:循環全部對象,所有是使用迭代器協議
(字符串,列表,元祖,字典,集合,文件對象),這些都不是可迭代對象,只不過在for循環,調用了他們內部的__iter__方法,把他們變成了可迭代對象。而後for循環調用可迭代對象的__next__方法去去找,而後for循環會自動捕捉StopIteration異常,來終止循環。
1 l1 = ["hello","world",1,2] 2 3 #for循環調用可迭代對象的__next__方法去取值,並且for循環會捕捉StopIteration異常,以終止對象 4 for i in l1: 5 print(i) 6 7 aa = l1.__iter__() #等同於內置函數aa = iter(l1) 建立了一個list_iterator 列表迭代器 8 print(type(aa)) 9 print(next(aa)) #內置函數 next()查看第一次迭代器的值 10 print(aa.__next__()) #迭代器自己對象的方法,第二次迭代器的值 跟 內置函數方法都是同樣的 11 print(next(aa)) 12 print(next(aa)) 13 print(next(aa)) #沒有可迭代的值了也就是迭代完了,會報錯:StopIteration 14 15 16 #迭代器迭代完,就不能再次迭代該迭代器 好比for 循環 17 for i in aa: 18 print(i)
1 # 首先得到Iterator對象: 2 it = iter([1, 2, 3, 4, 5]) #建立一個迭代器 3 # 循環: 4 while True: 5 try: 6 # 得到下一個值: 7 x = next(it) 8 print(x) 9 except StopIteration: 10 # 遇到StopIteration就退出循環 11 break
總結:
1.可做用於for循環對象自己都是iterable(可迭代對象)類型,或者對象自己有obj.__iter__方法也是iterable
2.凡是可做用於next()函數的對象自己itertor(迭代器)類型,或者obj.__next__也是iterator ,迭代器是一個惰性序列
由於須要調用next,纔會得到元素,迭代完,就不能再次迭代。
3.list、dict、str等是iterable,但不是iterator不過能夠經過iter()函數得到一個迭代器對象。
什麼是生成器?
1.從字面理解是否是:生成一個容器
2.在python中,一邊循環,一邊計算的機制,稱爲生成器(generator)。
3.能夠理解爲一種數據類型,這種類型自動實現了迭代器協議。(其餘的數據類型須要調用自已的內置__iter__方法或則iter()的內置函數),因此生成器就是一個可迭代對象。
生成器分類以及在python中的表現形式。(python有兩種不一樣的方式提供生成器)
1.生成器函數:常規函數定義,可是,使用yield語句而不是return語句的返回結果。yield語句一次返回一個結果,在每一個結果中間,保留函數的狀態,以便再上一次狀態的從新執行。
2.生成器表達式:相似於列表推導,可是生成器返回按需產生結果的一種對象,而不是一次構建一個結果列表
爲什麼使用生成器,生成器的優勢:
python使用生成器對延遲操做提供了支持。所謂延遲操做,是指須要的時候才產生結果,而不是當即生成結果
這就是生成器的好處
生成器小結:
1.生成器是可迭代對象
2.實現了延遲計算,看內存(按需,執行)
3.生成器本質和其餘類型同樣,都是實現了迭代器協議,只不過生成器是一邊計算,一邊生成,從而節省內存空間,
其他的可迭代對象可沒有好處。
定義生成器的前提:
1.考慮這個生成器是否須要屢次遍歷。
2.這個生成器內存空間的問題。
3.時間效率問題。
生成器是一個惰性的,根據惰性求值:也就是須要一個對象給一個對象
1.三元運算或則3元表達式
1 #三元表達式格式 2 3 res=值1 if 條件 else 值2 4 5 #若是條件知足 res 等於 值1 條件不知足就等於 值2 6 # demo 1 7 name = "xixi" 8 res = "xixi" if name == "xixi" else "hello" 9 print(res) 10 11 #demo 2 12 num = 2 if False else 0 13 print(num)
2.列表生成式
1 #列表生成式經過計算生成一個列表 2 3 lis_gen = [ i for i in range(1,10)] #列表生成式 4 print(lis_gen) 5 6 lis1_gen = [i for i in range(1,10) if i%2 == 0] #生成一個偶數的列表 7 print(lis1_gen) 8 9 lis2_gen = [ i * i for i in range(1,10) if i%2 == 1] #生成以個奇數乘自已自己奇數的列表 10 print(lis2_gen)
3.生成器表達式
1 gen_exp = (i for i in range(10)) #生成器表達式 2 print(gen_exp) #generator 3 # for i in gen_exp: #取出生成器表達式的值,for循環 4 # print(i) 5 print(gen_exp.__next__()) #next方法 6 print(gen_exp.__next__()) 7 print(gen_exp.__next__()) 8 print(gen_exp.__next__()) 9 print(gen_exp.__next__())
1 gen = (i for i in range(10**100)) #生成器表達式 2 lis = [i for i in range(10**100)] #列表生成式 3 4 #生成器,更省內存,須要一個取一個 5 print(gen.__next__()) 6 print(lis) #須要在內存空間建立1-10**100序列
總結:
1.把列表解析的[]換成()獲得就是生成器表達式
2.列表生成式式一個構建一個結果列表,生成器表達式:是返回按需產生結果的一個對象
3.列表解析與生成器表達式都是一種便利的編程方式,只不過生成器表達式更節省內存
4.python不但使用迭代器協議讓for循環更加通用,大部份內置函數,也是使用迭代器協議訪問對象的
如,sum函數是python的內置函數,該函數使用迭代器協議訪問對象,而生成器實現了迭代器協議
在python中,使用了yield的函數就稱爲生成器(generator)
1.跟普通函數不一樣的是,生成器是一個返回迭代器的函數,只能用於迭代操做,能夠理解爲:生成器就是一個迭代器
2.在調用生成器運行過程當中,每次遇到yield是函數會暫停並保存當前全部的運行信息,返回yield值。並在下一次執行next方法時,從當前位置繼續運行。
普通生成器:
1 >>> gen = (i for i in range(5)) 2 >>> gen 3 <generator object <genexpr> at 0x0000004DE29A70A0> 4 >>> next(gen) 5 0 6 >>> next(gen) 7 1 8 >>> next(gen) 9 2 10 >>> next(gen) 11 3 12 >>> next(gen) 13 4 14 >>> next(gen) 15 Traceback (most recent call last): 16 File "<stdin>", line 1, in <module> 17 StopIteration
注:generator保存的是算法,每次調用next方法,就計算出gen的下一個元素的值,直到計算到最後一個元素,沒有更多元素時,就StopIteration的錯誤。
固然,上面這種不斷調用next(gen),用着有點坑,正確的方法是使用for循環,由於generator也是iterator;
1 >>> g = (i for i in range(5)) 2 >>> for i in g: 3 ... print(i) 4 ... 5 0 6 1 7 2 8 3 9 4
因此咱們建立了一個generator後,基本不會調用next方法,而是經過for循環來迭代它,而且不是關心StopIteration的錯誤。
generator很是強大,若是計算的算法比較複雜,用for循環沒法實現的時候,還能夠用函數來實現。
例:斐波拉契數列 後面的一個數等於前面兩個數相加的和
1 def fib(number): 2 #得出幾個斐波拉契數列 3 count,a,b = 0,0,1 4 while count < number: 5 print(b) 6 a,b = b,a+b 7 count += 1 8 return "done" 9 fib(5)
1 def fib1(number): 2 n,a,b = 0,0,1 3 while n<number: 4 yield b 5 a,b = b,a+b 6 n += 1 7 return "done" 8 aa = fib1(6) 9 print(aa) #generator 10 # print(aa.__next__()) 11 for i in aa: 12 print(i)
注:若是一個函數定義中包含yield關鍵字,那麼這個函數就不是普通函數,而是一個generator
注:generator和函數執行的流程不同,
函數是順序執行,遇到return語句或則最後一行函數函數語句就返回。
而變成generator的函數,在每次調用next()的時候執行,遇到yield語句返回,再次執行從上次返回的yield語句處繼續執行
1 def packet(): 2 for i in range(1,10): 3 print("開始生產包子") 4 yield "第 %d 屜包子" %(i) 5 print("賣包子,買完再生產") 6 cs = packet() #生成一個作包子的生成器,至關於作包子的 7 # print(cs) 8 q = print(cs.__next__()) #賣包子的 9 print(cs.__next__()) 10 for i in cs: 11 print(i)
1 #單線程一邊發送,一邊執行 2 import time 3 def consumer(name): 4 print("%s 準備吃包子啦!" %name) 5 while True: 6 baozi = yield 7 8 print("包子[%s]來了,被[%s]吃了!" %(baozi,name)) 9 def producer(name): 10 c = consumer('A') 11 c2 = consumer('B') 12 c.__next__() 13 c2.__next__() 14 print("老子開始準備作包子啦!") 15 for i in range(10): 16 time.sleep(1) 17 print("作了2個包子!") 18 c.send(i) #發送的值,就是yield的返回值 19 c2.send(i) 20 producer("xixi")
1.生成器函數語法上和普通函數相似:生成器使用yield語句返回一個值,而常規函數使用return語句返回一個值
2.生成器自動實現迭代器協議,迭代完,就不能再次迭代。
3.狀態掛起:生成器使用yield語句返回一個值。掛起該生成器函數的狀態。