迭代器:iterator
可迭代對象:iterable
迭代器
在本文中,我們將學習迭代器是如何工作的,以及如何使用 __iter__()
和 __next__()
方法構建自己的迭代器。
迭代器(Iterator
)是可以迭代的對象,在 Python 中無處不在。它們在 for 循環、推導式、生成器等中得到了優雅的實現,但卻隱藏在顯而易見的地方。
Python 中的迭代器只是一個可以迭代的對象。一個每次僅僅返回一個元素的對象(有點像擠牙膏)。從技術上講,Python 迭代器對象必須實現兩個魔法方法:__iter__()
和 __next__()
方法,統稱為迭代器協議(iterator protocol)。
如果我們可以從一個對象中得到一個迭代器,那么這個對象就被稱為可迭代對象(iterable
)。Python 中的大多數內置數據結構(容器)都是可迭代對象,比如 list列表、 tuple元組、 str字符串等等。iter ()
函數(反過來調用__iter__()
方法)從它們中返回一個迭代器。
遍歷迭代器
我們使用 next()
函數手動遍歷迭代器的所有元素。當我們到達結尾時,如果沒有更多的數據要返回,它將引發 StopIteration
異常。
示例:
# 定義一個列表
my_list = [4, 7, 0, 3]
# 使用iter()返回一個迭代器對象
my_iter = iter(my_list)
# 使用next()方法依次遍歷
print(next(my_iter)) # 將打印 4
print(next(my_iter)) # 將打印 7
# next(obj) 和 obj.__next__()效果一樣
print(my_iter.__next__()) # 將打印 0
print(my_iter.__next__()) # 將打印 3
next(my_iter) # 將會引起 StopIteration 異常
輸出結果:
4
7
0
3
Traceback (most recent call last):
File "<string>", line 24, in <module>
next(my_iter)
StopIteration
一種更優雅的自動迭代方式是使用 for 循環。這樣一來,我們可以遍歷任何可以返回迭代器的對象,例如列表、字符串、文件等等。
示例:
# 定義一個列表
my_list = [4, 7, 0, 3]
# 使用for循環遍歷
for i in my_list:
print(i)
迭代器中的for循環
正如我們在上面的例子中看到的,for循環能夠自動遍歷列表。實際上,for 循環可以遍歷任何可迭代的對象。讓我們仔細看看 for 循環是如何在 Python 中實現的。
# 從可迭代對象中創建一個迭代器對象
iter_obj = iter(iterable)
# 開啟無限循環
while True:
try:
# 遍歷元素
element = next(iter_obj)
# 對元素進行一些操作
pass
except StopIteration:
# 如果引起StopIteration則終止循環
break
由此可見,for 循環在內部通過對可迭代對象(iterable
)調用 iter()
方法,來創建出一個迭代器(iterator
)對象 iter_obj
。
笑不活的是,這個 for循環實際上竟是一個無限 while循環......意不意外,驚不驚喜😂。
自定義迭代器
在 Python 中,從零開始構建迭代器很容易,我們只需要實現 __iter__()
和 __next__()
方法。
-
__iter__()
方法返回迭代器對象本身. 如果需要,可以執行一些初始化。 -
__next__()
方法必須返回序列中的下一項。在到達結尾時,以及在隨后的調用中,它必須引發StopIteration
異常。
下面,我們展示一個例子,它將給出每次迭代中2的下一次冪。其中冪指數從零開始到用戶設置的數字。
class PowTwo:
"""2的迭代器指數類"""
def __init__(self, max=0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max:
result = 2 ** self.n
self.n += 1
return result
else:
raise StopIteration
# 創建可迭代對象
numbers = PowTwo(3)
# 獲得一個迭代器
i = iter(numbers)
# 獲取下一個元素
print(next(i))
print(next(i))
print(next(i))
print(next(i))
執行后,輸出結果:
1
2
4
8
我們還可以使用 for 循環迭代迭代器類。
for i in PowTwo(5):
print(i)
執行后輸出結果:
1
2
4
8
16
32
無限迭代器
迭代器對象中的項不必用盡。可以有無限迭代器(它永遠不會結束)。在處理這樣的迭代器時,我們必須小心。
下面是演示無限迭代器的一個簡單示例。
內置函數 iter()
還有一種用法是:
iter(callable, sentinel) -> iterator
也就是說,它在調用時可以接收兩個參數 ,其中第一個參數必須是可調用對象(函數) ,第二個參數必須是哨兵。迭代器調用這個函數,直到返回的值等於哨兵。
我們知道python中的 int()
函數默認總是返回0。因此,將它作為 iter(int,1)
傳遞將返回一個調用 int()的迭代器,直到返回的值等於1。這種情況從來沒有發生,我們得到了一個無限迭代器。
不僅如此,我們還可以構建自己的無限迭代器。
class InfIter:
"""一個用來返回所有的奇數的無限迭代器類"""
def __iter__(self):
self.num = 1
return self
def __next__(self):
num = self.num
self.num += 2
return num
執行后輸出結果:
1
3
5
...
其中...表示后續輸出無窮無盡。
因此,在遍歷這些類型的無限迭代器時,要注意包含終止條件。
其實,Python中還有一種更簡單的創建迭代器的方法,就是使用生成器 generator
。
---END