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