python中有一類工具叫做迭代工具,它能從左至右掃瞄物件。這包括了for迴圈、列表解析、in成員關係測試以及map內建函式等。可以用在上述迭代工具環境中,通過一次次迭代不斷產生結果的物件稱為可迭代物件,即是iterable。
實際上可迭代物件分為兩大類,一種是實際儲存的序列,即列表、元組,字串;另一種就是 「不一次性產生所有結果列表,而是可以在for迴圈中按需一次產生乙個結果的物件」。如:range函式返回值、zip函式返回值、enumerate函式返回值等等,與實際序列相對應,這個叫做按需產生物件的虛擬序列。
而迭代器是乙個含有 next() 方法的物件,可以被next()函式不斷呼叫並返回下乙個值(迭代器從物件的第乙個元素開始訪問),直到所有的元素被遍歷後結束,超出範圍後能夠丟擲stopiteration的錯誤停止迭代。
迭代器可以使你迭代不是序列而表現出序列行為的物件,如字典的鍵、乙個檔案的行等。當你使用迴圈迭代乙個物件條目時,幾乎分不出它是迭代器還是序列,也不必去關心這些,python可以讓它像乙個序列那樣操作。
>>> from collections import iterable
>>> isinstance(,iterable)
true
>>> dir()
物件裡面包含__iter()__方法的實現,但它沒有next方法,不是乙個迭代器。
>>> from collections import iterator
>>> isinstance(,iterator)
false
>>> isinstance({},iterator)
false
>>> isinstance(str,iterator)
false
list、dict、str雖然是iterable,卻不是iterator,把list、dict、str等iterable變成iterator需要呼叫物件中的iter方法,呼叫成功後會返回乙個迭代器,裡面包含具體資料獲取的實現。迭代器為類序列物件提供了乙個類序列的介面(只要是實現了 __iter__() 方法的物件,就可以使用迭代器來進行訪問)。
>>> isinstance(iter(),iterator)
true
iter()函式實現將乙個可迭代物件轉換為迭代器,然後呼叫next()方法就可以按需取出元素。
>>> alist=[1,2,4,5,'a']
>>> iter_list=iter(alist) # invokes alist.__iter__()
>>> next(iter_list) # invokes iter_list.__next__()
>>> next(iter_list)
一般我們會使用for迴圈語句用來遍歷乙個可迭代物件,因此迭代器也可以作用於for迴圈語句,這樣可以將迭代器中元素依次取出
>>> alist=[1,2,4,5,'a']
>>> for i in alist:
... print(i,end=' ')
1 2 4 5 a
>>>iter_list= iter(alist) # invokes alist.__iter__()
>>> for i in iter_list:
... print(i,end=' ')
1 2 4 5 a
>>> next(iter_list) #迭代完畢,丟擲異常
traceback (most recent call last):
file "", line 1, in
next(iter_list)
stopiteration
# 首先獲得iterator物件:
it = iter(alist) # invokes alist.__iter__()
# 迴圈:
while true:
try:
# 依次獲得下乙個值:
x = next(it) # run the iterator, invokes it.__next__()
except stopiteration:
# 遇到stopiteration就退出迴圈
break
for這個語法背後的是首先獲取可迭代物件返回的迭代器物件,然後不斷呼叫迭代器物件的next方法獲取每個值,在獲取值的過程中隨時檢測邊界-也就是檢查是否丟擲了stopiteration這樣的異常,如果迭代器物件丟擲錯誤則迭代停止,異常只是告訴外部呼叫者,迭代完成。
或者當任何可迭代物件傳入到for迴圈或其他迭代工具(如list)中進行遍歷時,迭代工具都是先通過iter函式獲得與可迭代物件對應的迭代器,然後再對迭代器呼叫next函式,不斷的依次獲取元素,並在捕捉到stopiteration異常時確定完成迭代,這就是完整的迭代過程。這也稱之為「迭代協議」。
使用迭代器的理由
首先看那麼為什麼list、dict、str等資料型別不是iterator?
這是因為python的iterator物件表示的是乙個資料流,iterator物件可以被next()函式呼叫並不斷返回下乙個資料,直到沒有資料時丟擲stopiteration錯誤。可以把這個資料流看做是乙個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()函式實現按需計算下乙個資料,所以iterator的計算是惰性的,只有在需要返回下乙個資料時它才會計算。iterator甚至可以表示乙個無限大的資料流,例如全體自然數。而使用list是永遠不可能儲存全體自然數的。
它與列表的區別在於,構建迭代器的時候,不像列表把所有元素一次性載入到記憶體中,而是一種延時計算方式返回元素,如列表中含有一億個資料(假如整型佔4個位元組),需要記憶體400m,而迭代器只需要幾十個位元組的空間,這是因為它沒有把所有元素載入到記憶體中,而是等待呼叫next方法才返回該元素(按需呼叫call by need的方式)。
1、「流式」資料處理方式減少記憶體消耗:
比如處理檔案,一下猛地把全部資料全部取出來放到記憶體裡面進行處理會導致程式消耗大量記憶體,有時甚至沒法做到,一般我們會一部分一部分的對檔案內容進行處理:
for text_line in open("xx.txt"):
print text_line
open("xx.txt")返回的檔案物件是迭代器,所以可以漸進式地對檔案的內容進行處理,即按行來讀取檔案(自動呼叫readline()方法),並進行處理,而不是直接把全部檔案一下載入到記憶體中。
如下讀取乙個大檔案,要求輸出相同時間戳內狀態為200的平均連線數
#序號 時間戳 連線數 轉態碼
[root@localhost newtest]# cat cookies.txt
1 12345 12 200
2 12345 11 100
3 12345 19 200
4 12346 11 200
5 12346 19 200
6 12347 11 200
7 12348 10 200
8 12348 11 100
9 12348 11 200
10 12348 12 200
統計指令碼
def linknumpersecond(filename):
fp=open(filename,'r')
fronttimestamp=0 #初始狀態
persecondlinknum=0
cnt=0
for line in fp:
linelist = line.split(' ') #當前處理結果
status = linelist[3].strip('\n')
timestamp = linelist[1]
linknum=int(linelist[2])
if timestamp==fronttimestamp and status=='200':
persecondlinknum+=linknum
cnt+=1
else:
if timestamp !=fronttimestamp: #如果和上一次不一樣,就輸出上一次的統計結果
print(fronttimestamp,persecondlinknum,cnt)
if status=='200':
persecondlinknum=linknum #重新計算新的時間戳對應的連線數
fronttimestamp=timestamp
print(fronttimestamp,persecondlinknum,cnt) #最後的時間戳
測試用例
>>> linknumpersecond('/newtest/cookies.txt')
(0, 0, 0)
('12345', 31, 1)
('12346', 30, 2)
('12347', 11, 2)
('12348', 33, 4)
2、支援方便用for語句對資料進行處理
python內建的一些常見的型別像陣列、列表甚至字串等都是可迭代型別,這樣我們就能方便for語句這個語法方便對資料進行消費,不需要自己記錄索引位置。
1、在字典和列表中迭代會帶來效能上的提公升
2、迭代非序列集合(如對映、檔案)時,**更簡潔可讀
python迭代器的作用 python的迭代器
迭代是指能夠從序列中訪問出素的一種方式,在我們遍歷使用for.in.的物件都是可迭代物件。這裡需要補充一點的是python中一切都是物件。判斷乙個物件是否是可迭代物件可以通過instance函式 像我們常用的列表,字典,字串,集合,元組都是可迭代物件。那麼我們是否可以自定義乙個可迭代物件呢,答案是肯...
迭代器的作用
迭代器1 import time class classmates object def init self self.names list defadd self,name def iter self 如果想要乙個物件成為乙個可以迭代的物件,即可以使用for,那麼必須實現 iter 方法 retu...
迭代器的作用
迭代器就是把不同的資料結構 相同功能 的函式裝到乙個名字相同的函式裡,這樣的話你在寫演算法的時候就可以不管你要操作的資料結構的邏輯結構了。比如不管是鍊錶,陣列還是別的什麼,統一都用迭代器進行訪問的話可能都是 next 表示下乙個元素 pre 表示上乙個元素等等 其實意思就是,不管你用的是鍊錶,2叉樹...