環境說明: python3.7
通過查閱各類資料,總結一下疊代器相關知識,作為資料留存,友善以後查閱溫習。
一、什麼是疊代器
疊代器是實作了__next__()方法的對象(這個方法在調用時不需要任何參數),它是通路可疊代序列的一種方式,通常其從序列的第一個元素開始通路,直到所有的元素都被通路才結束。 [注意]:疊代器隻能前進不能後退
[疊代器的優點]:
使用疊代器不要求事先準備好整個疊代過程中的所有元素。疊代器僅僅在疊代到某個元素時才計算該元素,而在這之前或之後元素可以不存在或者被銷毀。是以疊代器适合周遊一些數量巨大甚至無限的序列。
以python2.x中的range函數和xrange函數為例,range函數傳回的是清單,xrange函數傳回的是疊代器,是以range函數占用的記憶體空間比xrange大,是以,在python3.x中,改進range函數傳回疊代器,取消xrange函數。
二、建立疊代器
(一)使用iter(iterable)可将可疊代序列轉換為疊代器
a=[1,2,3,4]
b=(1,2,3)
str='Tomwenxing'
print(iter(a))
print(iter(b))
print(iter(str))
輸出如下:
<list_iterator object …>
<tuple_iterator object …>
<str_iterator object …>
說明: 并不是所有的資料類型/結構都能轉換為疊代器,清單、元組、字元串等本身就是iterable,是以可以通過iter函數生成疊代器。
(二)自定義支援iterable的類
與上面“說明”一緻,如果我們定義了一個支援iterable的類,那麼我們也可以使用iter函數生成對應的疊代器。
Python中疊代器的本質,每次調用__next__()方法都傳回下一個元素或抛出StopIteration的容器對象
由于Python中沒有“疊代器”這個類,是以具有以下兩個特性的類都可以稱為“疊代器”類:
1、有__next__()方法,傳回容器的下一個元素或抛出StopIteration異常
2、有__iter__()方法,傳回疊代器本身
如下例所示,通過在Fib類中定義上述兩個函數,就可以認為Fib是支援iterable。
class Fib(object):
def __init__(self,length):
self.length=length
self.curLength,self.preNum,self.curNum=0,0,1
def __iter__(self):
return self
def __next__(self):
if self.curLength<self.length:
r=self.curNum
self.preNum,self.curNum=self.curNum,self.preNum+self.curNum
self.curLength=self.curLength+1
return r
raise StopIteration()
if __name__=="__main__":
length=5
for n in Fib(length):
print(n)
輸出如下:
1
1
2
3
5
(三)生成器可看成是一個疊代器
在 Python 中,使用了 yield 的函數被稱為生成器(generator)。
yield 的作用就是把一個函數變成一個 generator,帶有 yield 的函數不再是一個普通函數,Python 解釋器會将其視為一個 generator,調用該函數不會執行,而是傳回一個生成器對象(generator 對象)。生成器對象可看成是一個疊代器對象,使用方法一樣。
在調用生成器運作的過程中,每次遇到 yield 時函數會暫停并儲存目前所有的運作資訊,傳回 yield 的值, 并在下一次執行 next() 方法時從目前位置繼續運作。
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
if __name__ == '__main__':
f = fibonacci(10) # f 是一個生成器,可看成是一個疊代器。
print(type(f))
輸出如下:
<class ‘generator’>
三、疊代器的使用
(一)使用next函數疊代
例1:
a=[1,2,3,4]
it=iter(a)
print(next(it))
print(next(it))
例2:
class Fib(object):
def __init__(self,length):
self.length=length
self.curLength,self.preNum,self.curNum=0,0,1
def __iter__(self):
return self
def __next__(self):
if self.curLength<self.length:
r=self.curNum
self.preNum,self.curNum=self.curNum,self.preNum+self.curNum
self.curLength=self.curLength+1
return r
raise StopIteration()
if __name__=="__main__":
fib=Fib(5)
print(next(fib))
it=iter(fib)
print(next(it))
特别說明: 通過上述案例,總結:Fib類的對象可直接被next函數調用疊代,Fib類的對象轉換成疊代器後也可被next函數調用疊代。疑問:與可疊代序列類比,Fib類對象不是應該轉換成疊代器後才可被next函數調用嗎,為什麼可直接被next函數調用?什麼原理,怎麼個過程啊,請大神指教!
例3:
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器函數 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
if __name__ == '__main__':
f = fibonacci(10) # f 是一個生成器,可看成是一個疊代器。
print(type(f))
print(next(f))
(二)使用for循環疊代
如下例:
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器函數 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
if __name__ == '__main__':
f = fibonacci(10) # f 是一個生成器,可看成是一個疊代器。
print(type(f))
for num in f:
print(num)
特别說明: 在執行for循環時,每執行一次,暗含會調用一次next函數。