一、迭代器介紹
迭代器即用來迭代取值的工具,而迭代是重複反饋過程的活動
,其目的通常是爲了逼近所需的目標或結果,每一次對過程的重複稱爲一次“迭代”,而每一次迭代得到的結果會作爲下一次迭代的初始值,單純的重複並不是迭代
goods=['mac','lenovo','acer','dell','sony']
index=0
while index < len(goods):
print(goods[index])
index+=1
下述while循環纔是一個迭代過程,不僅滿足重複
,而且以每次重新賦值後的index值作爲下一次循環中新的索引進行取值,反覆迭代,最終可以取盡列表中的值
注意:
- 上面這個迭代方法只適合序列類型,並不適合字典、集合、文件對象的迭代取值。
- 有人會說for循環可以對字典、文件對象、集合進行循環取值,其實
for循環就用到了迭代器
,因此這裏沒有用for循環爲例說明
1、可迭代對象
通過索引
的方式進行迭代取值,實現簡單,但僅適用於序列
類型:字符串,列表,元組。對於沒有索引的字典、集合、文件對象等非序列類型,必須找到一種不依賴索引來進行迭代取值的方式,這就用到了迭代器。
可迭代對象(Iterable)。從語法形式上講,內置有__iter__方法的對象都是可迭代對象
,字符串、列表、元組、字典、集合、打開的文件都是可迭代對象。
{'name':'吳晉丞'}.__iter__
{7,8,9}.__iter__
……
2、迭代器對象
調用obj.iter()方法返回的結果就是一個迭代器對象(Iterator)
。
除文件對象外,字典、集合、列表等都只是可迭代對象而已
,它們可以通過調用iter方法生成迭代器對象,並進行迭代取值。但文件對象在python中使用時,直接生成的就是迭代器對象
,當然它也是可迭代對象。文件對象可以直接調用next函數
,只有迭代器對象才能調用next方法,因此文件對象是迭代器對象。執行迭代器對象.iter()方法
得到的仍然是迭代器本身
,而執行迭代器對象.next()方法
就會計算出迭代器中的下一個值
。
>>> s={1,2,3} # 可迭代對象s
>>> i=iter(s) # 本質就是在調用s.__iter__(),返回s的迭代器對象i,
>>> next(i) # 本質就是在調用i.__next__()
1
>>> next(i)
2
>>> next(i)
3
>>> next(i) #拋出StopIteration的異常,代表無值可取,迭代結束,要想繼續取值,除非在重新生成一個迭代器。
爲什麼文件對象要直接設置成迭代器對象,集合、字典等不設置成迭代器對象呢?
答:首先我們應該明白迭代器這種需要一個值,next方法取一個值,這樣是降低了內存的消耗的。集合、字典等定義下來,本來就不是用來存很多、很多東西的。但是一個文件對象卻可以很大很大,因此必須直接生成迭代器對象,控制內存的消耗。
二、for循環原理
有了迭代器後,我們便可以不依賴索引迭代取值了,使用while循環的實現方式如下
dic = {'a':1,'b':2,'c':3}
d_iterator = iter(dic) #d_iterator便是一個迭代器對象,iter方法生成的就是一個迭代器對象
while True: # while循環的循環體是進行循環迭代取值的
try:
print(next(d_iterator))
except(StopIteration): # 捕獲異常
break # 異常處理
for循環又稱爲迭代循環,in後可以跟任意可迭代對象
,上述while循環可以簡寫爲:
dic = {'a':1,'b':2,'c':3}
for i in dic:
print(item)
for 循環在工作時,首先會調用可迭代對象goods內置的iter方法
拿到一個迭代器對象,然後再調用該迭代器對象的next方法將取到的值賦給i
,執行循環體完成一次循環,周而復始,直到捕捉StopIteration異常,結束迭代
。
爲什麼文件對象中也需要有iter方法呢?
它不是已經是迭代器對象了嗎,而且前面說迭代器調用iter方法屁用沒有,得到的還是本身。
答:這是一個專門爲統一for循環而設計的,因爲for循環中你不確定自己in後面到底是不是迭代器對象,難道還要判斷一下嗎?那不是太麻煩了,無論誰來,只要可迭代,我就給你iter方法一下,即使是文件對象,也不影響啥。所以文件對象也需要一個iter方法,拿去讓for循環調用。
三、迭代器的優缺點
基於索引的迭代取值,所有迭代的狀態(迭代的位置信息)都保存在了索引
中,而基於迭代器實現迭代的方式不再需要索引,所有迭代的狀態就保存在迭代器
中,然而這種處理方式優點與缺點並存:
1、優點
(1)爲序列和非序列類型提供了一種統一的迭代取值方式。
(2)惰性計算:迭代器對象表示的是一個數據流,可以只在需要時纔去調用next來計算出一個值,就迭代器本身來說,同一時刻在內存中只有一個值,因而可以存放無限大的數據流
,而對於其他容器類型
,如列表,需要把所有的元素都存放於內存中
,受內存大小的限制,可以存放的值的個數是有限的
。
2、缺點
(1)除非取盡,否則無法獲取迭代器的長度
(2)只能取下一個值,不能回到開始,更像是'一次性的'
,迭代器產生後的唯一目標就是重複執行next方法直到值取盡,否則就會停留在某個位置,等待下一次調用next;若是要再次迭代同個對象,你只能重新調用iter方法去創建一個新的迭代器對象
,如果有兩個或者多個循環使用同一個迭代器,必然只會有一個循環能取到值
。