python基礎---迭代器和生成器

什麼叫迭代

現在,我們已經獲得了一個新線索,有一個叫做“可迭代的”概念。
首先,我們從報錯來分析,好像之所以1234不可以for循環,是因爲它不可迭代。那麼如果“可迭代”,就應該可以被for循環了。
這個我們知道呀,字符串、列表、元組、字典、集合都可以被for循環,說明他們都是可迭代的。
我們怎麼來證明這一點呢?

from collections import Iterable  
l = [1,2,3,4]     
d = {1:2,3:4}             
s = {1,2,3,4}                                             
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(d,Iterable))
print(isinstance(s,Iterable))

結合我們使用for循環取值的現象,再從字面上理解一下,其實迭代就是我們剛剛說的,可以將某個數據集內的數據“一個挨着一個的取出來”,就叫做迭代。

可迭代協議

我們現在是從結果分析原因,能被for循環的就是“可迭代的”,但是如果正着想,for怎麼知道誰是可迭代的呢?
假如我們自己寫了一個數據類型,希望這個數據類型裏的東西也可以使用for被一個一個的取出來,那我們就必須滿足for的要求。這個要求就叫做“協議”。
可以被迭代要滿足的要求就叫做可迭代協議。可迭代協議的定義非常簡單,就是內部實現了iter方法。
接下來我們就來驗證一下:

print(dir([1,2]))
print(dir((2,3)))
print(dir({1:2}))
print(dir({1,2}))

結果
總結一下我們現在所知道的:可以被for循環的都是可迭代的,要想可迭代,內部必須有一個iter方法。
接着分析,iter方法做了什麼事情呢?
print([1,2].iter())結果
執行了list([1,2])的iter方法,我們好像得到了一個list_iterator,現在我們又得到了一個新名詞——iterator。
這裏寫圖片描述
iterator,這裏給我們標出來了,是一個計算機中的專屬名詞,叫做迭代器。

迭代器協議

既什麼叫“可迭代”之後,又一個歷史新難題,什麼叫“迭代器”?
雖然我們不知道什麼叫迭代器,但是我們現在已經有一個迭代器了,這個迭代器是一個列表的迭代器。
我們來看看這個列表的迭代器比起列表來說實現了哪些新方法,這樣就能揭開迭代器的神祕面紗了吧?

'''dir([1,2].__iter__())是列表迭代器中實現的所有方法,dir([1,2])是列表中實現的所有方法,都是以列表的形式返回給我們的,爲了看的更清楚,我們分別把他們轉換成集合,
然後取差集。'''

#print(dir([1,2].__iter__()))
#print(dir([1,2]))
print(set(dir([1,2].__iter__()))-set(dir([1,2])))
# 結果:{'__length_hint__', '__next__', '__setstate__'}

我們看到在列表迭代器中多了三個方法,那麼這三個方法都分別做了什麼事呢?

iter_l = [1,2,3,4,5,6].__iter__()#獲取迭代器中元素的長度
print(iter_l.__length_hint__())#根據索引值指定從哪裏開始迭代
print('*',iter_l.__setstate__(4))#一個一個的取值
print('**',iter_l.__next__())print('***',iter_l.__next__())

這三個方法中,能讓我們一個一個取值的神奇方法是誰?
沒錯!就是__next__

在for循環中,就是在內部調用了next方法才能取到一個一個的值。
那接下來我們就用迭代器的next方法來寫一個不依賴for的遍歷。

l = [1,2,3,4]
l_iter = l.__iter__()
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)

這是一段會報錯的代碼,如果我們一直取next取到迭代器裏已經沒有元素了,就會拋出一個異常StopIteration,告訴我們,列表中已經沒有有效的元素了。
這個時候,我們就要使用異常處理機制來把這個異常處理掉。

l = [1,2,3,4]
l_iter = l.__iter__()
while True:    
try:        
    item = l_iter.__next__()        
    print(item)    
except StopIteration:       
     break

那現在我們就使用while循環實現了原本for循環做的事情,我們是從誰那兒獲取一個一個的值呀?是不是就是l_iter?好了,這個l_iter就是一個迭代器。
迭代器遵循迭代器協議:必須擁有iter方法和next方法。
還賬:next和iter方法
如此一來,關於迭代器和生成器的方法我們就還清了兩個,最後我們來看看range()是個啥。首先,它肯定是一個可迭代的對象,但是它是否是一個迭代器?我們來測試一下
range函數的返回值是一個可迭代對象

爲什麼要有for循環

基於上面講的列表這一大堆遍歷方式,聰明的你立馬看除了端倪,於是你不知死活大聲喊道,你這不逗我玩呢麼,有了下標的訪問方式,我可以這樣遍歷一個列表啊
l=[1,2,3]index=0while index < len(l): print(l[index]) index+=1#要毛線for循環,要毛線可迭代,要毛線迭代器
沒錯,序列類型字符串,列表,元組都有下標,你用上述的方式訪問,perfect!但是你可曾想過非序列類型像字典,集合,文件對象的感受,所以嘛,年輕人,for循環就是基於迭代器協議提供了一個統一的可以遍歷所有對象的方法,即在遍歷之前,先調用對象的iter方法將其轉換成一個迭代器,然後使用迭代器協議去實現循環訪問,這樣所有的對象就都可以通過for循環來遍歷了,而且你看到的效果也確實如此,這就是無所不能的for循環,覺悟吧,年輕人
返回頂部

初識生成器

我們知道的迭代器有兩種:一種是調用方法直接返回的,一種是可迭代對象通過執行iter方法得到的,迭代器有的好處是可以節省內存。
如果在某些情況下,我們也需要節省內存,就只能自己寫。我們自己寫的這個能實現迭代器功能的東西就叫生成器。
Python中提供的生成器:
1.生成器函數:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行
2.生成器表達式:類似於列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建一個結果列表
生成器Generator:
  本質:迭代器(所以自帶了iter方法和next方法,不需要我們去實現)
  特點:惰性運算,開發者自定義
返回頂部

生成器函數

一個包含yield關鍵字的函數就是一個生成器函數。yield可以爲我們從函數中返回值,但是yield又不同於return,return的執行意味着程序的結束,調用生成器函數不會得到返回的具體的值,而是得到一個可迭代的對象。每一次獲取這個可迭代對象的值,就能推動函數的執行,獲取新的返回值。直到函數執行結束。
初識生成器函數
生成器有什麼好處呢?就是不會一下子在內存中生成太多數據

假如我想讓工廠給學生做校服,生產2000000件衣服,我和工廠一說,工廠應該是先答應下來,然後再去生產,我可以一件一件的要,也可以根據學生一批一批的找工廠拿。
而不能是一說要生產2000000件衣服,工廠就先去做生產2000000件衣服,等回來做好了,學生都畢業了。。。
初識生成器二
更多應用
生成器監聽文件輸入的例子
計算移動平均值(1)
計算移動平均值(2)_預激協程的裝飾器
yield from
yield from

列表推導式和生成器表達式
總結:
1.把列表解析的[]換成()得到的就是生成器表達式
2.列表解析與生成器表達式都是一種便利的編程方式,只不過生成器表達式更節省內存
3.Python不但使用迭代器協議,讓for循環變得更加通用。大部分內置函數,也是使用迭代器協議訪問對象的。例如, sum函數是Python的內置函數,該函數使用迭代器協議訪問對象,而生成器實現了迭代器協議,所以,我們可以直接這樣計算一系列值的和:
sum(x ** 2 for x in range(4))
而不用多此一舉的先構造一個列表:
sum([x ** 2 for x in range(4)])
更多精彩請見——迭代器生成器專題:http://www.cnblogs.com/Eva-J/articles/7276796.html

本章小結

可迭代對象:
  擁有iter方法
  特點:惰性運算
  例如:range(),str,list,tuple,dict,set
迭代器Iterator:
  擁有iter方法和next方法
  例如:iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),reversed(list_o),map(func,list_o),filter(func,list_o),file_o
生成器Generator:
  本質:迭代器,所以擁有iter方法和next方法
  特點:惰性運算,開發者自定義
使用生成器的優點:
1.延遲計算,一次返回一個結果。也就是說,它不會一次生成所有的結果,這對於大數據量處理,將會非常有用。
列表解析式和生成器表達式
2.提高代碼可讀性

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章