疊代器
疊代是Python最強大的功能之一,是通路集合元素的一種方式。
疊代器是一個可以記住周遊的位置的對象,簡單的說,就是他隻記錄資料在記憶體中所在的位置,使用的是棧的邏輯記錄資料所在的記憶體位址,因為用的是棧的邏輯,是以隻需要記住棧的起始位址,以及棧的偏移量就可以得到所有資料的記憶體位址。
疊代器對象從集合的第一個元素開始通路,直到所有的元素被通路完結束。疊代器隻能往前不會後退。是以,疊代器可以存儲很多資料,而不占用很多記憶體空間,但是這個特性也導緻它無法反複讀資料,也就是“閱完即焚”。
疊代器有兩個基本的方法:iter() 和 next()。
字元串,清單或元組對象都可用于建立疊代器:
list=[1,2,3,4]
it = iter(list) # 建立疊代器對象
print(it)
# 輸出結果:<list_iterator object at 0x000001499C6EA400>
print (next(it)) # 輸出疊代器的下一個元素
# 輸出結果:1
print (next(it))
# 輸出結果:2
由此可以看出,疊代器并不能直接輸出結果,他傳回的值是一個疊代器對象,隻能使用next方法來提取疊代器下一個元素。
那麼如果疊代器裡的資料很多,總不能一個接一個next的吧。
當然python肯定不會那麼蠢,是以疊代器對象也可以使用正常for語句進行周遊:
list=[1,2,3,4]
it = iter(list) # 建立疊代器對象
for x in it:
print (x, end=" ")
# 輸出結果:1 2 3 4
或者,while循環調用next提取元素
import sys # 引入 sys 子產品
list=[1,2,3,4]
it = iter(list) # 建立疊代器對象
while True:
try:
print (next(it),end=" ")
except StopIteration:
sys.exit()
# 輸出結果:1 2 3 4
建立一個疊代器
把一個類作為一個疊代器使用,需要在類中實作兩個方法 __iter__() 與 __next__() 。
如果你已經了解的面向對象程式設計,就知道類都有一個構造函數,Python 的構造函數為 __init__(), 它會在對象初始化的時候執行。
__iter__() 方法傳回一個特殊的疊代器對象, 這個疊代器對象實作了 __next__() 方法并通過 StopIteration 異常辨別疊代的完成。
__next__() 方法(Python 2 裡是 next())會傳回下一個疊代器對象。
為了友善說明這兩個方法,我們來建立一個傳回數字的疊代器,初始值為 1,逐漸遞增 1,并通過__next__()傳回遞增後的值:
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
'''
輸出結果:
1
2
3
4
5
'''
StopIteration
剛剛提到了StopIteration,這是什麼呢?這是一種異常,用于辨別疊代的完成,防止出現無限循環的情況,在 __next__() 方法中我們可以設定在完成指定循環次數後,通過raise觸發 StopIteration 異常來結束疊代。
比如,想要寫一個程式,在資料 20 次疊代後停止執行運作,那麼可以這麼寫:
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration
myclass = MyNumbers()
myiter = iter(myclass)
for x in myiter:
print(x)
'''
輸出結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
'''
生成器
ok~說完疊代器,那麼我們再來看一個更神奇的内容,為什麼說它神奇呢?
因為在 Python 中,使用了 yield 的函數被稱為生成器(generator)。跟普通函數不同的是,生成器是一個傳回疊代器的函數,隻能用于疊代操作,更簡單點了解生成器就是一個疊代器,是以生成器生成的資料也隻能使用一次,“閱完即焚”。
在調用生成器運作的過程中,每次遇到 yield 時函數會暫停并儲存目前所有的運作資訊,傳回 yield 的值, 并在下一次執行 next() 方法時從目前位置繼續運作。
調用一個生成器函數,則會傳回的是一個疊代器對象。
我們使用 yield 來實作斐波那契數列,借此看一下生成器是什麼邏輯:
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
f = fibonacci(10) # f 是一個疊代器,由生成器傳回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
# 輸出結果:0 1 1 2 3 5 8 13 21 34 55
結束語
至此,我們說完了疊代器與生成器,總而言之,疊代器就是一個集合,他記錄了資料所在記憶體位址,然後以棧的形式儲存這些記憶體位址,是以python隻需要記住集合的開始位址和偏移量,就可以得到周遊集合,然後根據集合中的每一個記憶體位址就可以得到資料。
生成器就是一個特殊的疊代器,他是一個生成疊代對象的函數,通過yield來生成疊代對象中的每一個元素。