迭代器是可以迭代的對象。 在本教程中,您將學習迭代器的工作原理以及如何使用__iter__和__next__方法構(gòu)建自己的迭代器。
迭代器在Python中無處不在。它們在for循環(huán),理解,生成器等中優(yōu)雅地實現(xiàn),但卻隱藏在眼皮底下。
Python中的Iterator只是一個可以迭代的對象。一個將返回數(shù)據(jù)的對象,一次返回一個元素。
從技術(shù)上講,Python 迭代器對象必須實現(xiàn)兩個特殊方法,__iter__()和__next__()統(tǒng)稱為迭代器協(xié)議。
如果我們可以從對象獲得迭代器,則該對象稱為可迭代。Python中的大多數(shù)內(nèi)置容器(例如:list,tuple,string等)都是可迭代的。
iter()函數(shù)(也就是__iter__()方法)從它們返回一個迭代器。
我們使用該next()函數(shù)手動遍歷迭代器的所有項目。 當我們到達末尾并且沒有更多數(shù)據(jù)要返回時,它將引發(fā)StopIteration。 以下是一個示例。。
# 定義一個列表 my_list = [4, 7, 0, 3] # 使用iter()獲得迭代器 my_iter = iter(my_list) ## 使用iter()獲得迭代器 #輸出 4 print(next(my_iter)) #輸出 7 print(next(my_iter)) ## next(obj)與obj .__ next __()相同 #輸出 0 print(my_iter.__next__()) #輸出 3 print(my_iter.__next__()) ## 這將引起錯誤,沒有項目剩下 next(my_iter)
一種自動迭代的更優(yōu)雅的方法是使用for循環(huán)。使用此方法,我們可以迭代可以返回迭代器的任何對象,例如列表,字符串,文件等。
>>> for element in my_list: ... print(element) ... 4 7 0 3
正如我們在上面的示例中看到的那樣,for循環(huán)能夠自動遍歷列表。
實際上,for循環(huán)可以迭代任何可迭代的對象。讓我們仔細看看如何for在Python中實際實現(xiàn)循環(huán)。
for element in iterable: # 對元素做點什么
實際上是實現(xiàn)為。
# 創(chuàng)建一個迭代器對象iterable iter_obj = iter(iterable) # 無限循環(huán) while True: try: # 獲取下一項 element = next(iter_obj) # 對元素做點什么 except StopIteration: # 如果引發(fā)StopIteration,則從循環(huán)中斷 break
因此,在內(nèi)部,for循環(huán)通過在iterable上調(diào)用iter()創(chuàng)建一個迭代器對象iter_obj。
具有諷刺意味的是,這個for循環(huán)實際上是一個無限的while循環(huán)。
在循環(huán)內(nèi)部,它調(diào)用next()來獲取下一個元素,并使用這個值執(zhí)行for循環(huán)的主體。當所有的項都用完后,StopIteration被拋出,它在內(nèi)部被捕獲,循環(huán)結(jié)束。注意,任何其他類型的異常都會通過。
在Python中從頭開始構(gòu)建迭代器很容易。我們只需要實現(xiàn)這些方法__iter__()和__next__()。
__iter__()方法返回迭代器對象本身。如果需要,可以執(zhí)行一些初始化。
__next__()方法必須返回序列中的下一項。在到達終點時,以及在隨后的調(diào)用中,它必須引發(fā)StopIteration。
這里,我們展示了一個示例,它將在每次迭代中為我們提供2的次冪。冪指數(shù)從0到用戶設置的數(shù)字。
class PowTwo: """實現(xiàn)迭代器的類 二的冪""" 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
現(xiàn)在,我們可以創(chuàng)建一個迭代器,并如下進行迭代。
>>> a = PowTwo(4) >>> i = iter(a) >>> next(i) 1 >>> next(i) 2 >>> next(i) 4 >>> next(i) 8 >>> next(i) 16 >>> next(i) Traceback (most recent call last): ... StopIteration
我們還可以使用for循環(huán)來迭代迭代器類。
>>> for i in PowTwo(5): ... print(i) ... 1 2 4 8 16 32
迭代器對象中的項不必耗盡??赡苡袩o限的迭代器(永遠不會結(jié)束)。在處理這樣的迭代器時,我們必須小心。
這是一個演示無限迭代器的簡單示例。
內(nèi)置函數(shù) iter()可以用兩個參數(shù)調(diào)用,其中第一個參數(shù)必須是可調(diào)用對象(函數(shù)),第二個參數(shù)是標記。迭代器調(diào)用這個函數(shù),直到返回的值等于標記值為止。
>>> int() 0 >>> inf = iter(int,1) >>> next(inf) 0 >>> next(inf) 0
我們可以看到int()函數(shù)始終返回0。因此,將其作為iter(int,1)傳遞將返回一個迭代器,該迭代器調(diào)用int()直到返回值等于1。這永遠不會發(fā)生,并且我們得到一個無限迭代器。
我們還可以構(gòu)建自己的無限迭代器。理論上,以下迭代器將返回所有奇數(shù)。
class InfIter: """無限迭代器返回所有 奇數(shù)""" def __iter__(self): self.num = 1 return self def __next__(self): num = self.num self.num += 2 return num
運行如下。
>>> a = iter(InfIter()) >>> next(a) 1 >>> next(a) 3 >>> next(a) 5 >>> next(a) 7
等等...
在這些類型的無限迭代器上進行迭代時,請小心包含終止條件。
使用迭代器的優(yōu)點是節(jié)省了資源。如上所示,我們無需將整個數(shù)字系統(tǒng)存儲在內(nèi)存中就可以獲得所有奇數(shù)。從理論上講,我們可以在有限內(nèi)存中包含無限項。
迭代器還使我們的代碼看起來很酷。
有一種在Python中創(chuàng)建迭代器的簡便方法。要了解更多信息,請訪問:Python生成器yield。