摘要:對于迭代器來說,返回的是它自身,則是返回迭代器中的下一個值,如果沒有值了則拋出一個的異常。有一點繞,我們再來理一理迭代器和可迭代這兩個的差別一個迭代器一定是可迭代對象,因為它一定有方法。而可迭代對象的方法通常會生成一個新的迭代器對象。
for 循環(huán) 是我們在 Python 里非常常用的一個語法,但你有沒有思考過 for 循環(huán)是怎樣實現(xiàn)的?
如果你以前接觸過 C++,應(yīng)該會知道類似 for (int i = 0; i < 100; i++) 這樣的寫法,它定義了 循環(huán)的執(zhí)行條件 i < 100 以及 每次循環(huán)結(jié)束后執(zhí)行的語句 i++,而 for 本身只起到讓代碼重復執(zhí)行的作用,并沒有什么額外的功能。這在 Python 中其實更像是 while 循環(huán):
i = 0 while i < 100: # 執(zhí)行循環(huán)代碼 i += 1
但 Python 里的 for 循環(huán)卻不一樣。使用 for 時,我們沒有額外指定結(jié)束條件,也不需要一個用來計數(shù)的數(shù)值,甚至可以通過一個字符串進行循環(huán)。之所以可以這樣,是因為 Python 中的 迭代器(Iterator) 以及 可迭代對象(Iterable) 。
如果一個對象定義了 __iter__ 和 __next__ 兩個方法, 它就是一個迭代器 。對于迭代器來說,__iter__ 返回的是它自身 self ,__next__ 則是 返回迭代器中的下一個值 ,如果沒有值了則拋出一個 StopIteration 的異常。關(guān)于這點,你可以想象成一個只進不退的標記位,每次調(diào)用 __next__,就會將標記往后移一個元素并返回,直到結(jié)束。
有了迭代器的概念之后,如果一個對象定義了 __iter__ 和方法,返回一個迭代器對象,那么 它就是一個可迭代的對象 。
從表現(xiàn)上來說,一個對象 可迭代 ,那么它就可以被 for 循環(huán)使用。比如我們經(jīng)常用到的 list、dict、str 等類型,都是可迭代的,所以也就可以通過 for 循環(huán)進行遍歷,或者更準確的說:被迭代。
有一點繞,我們再來理一理迭代器(Iterator)和可迭代(Iterable)這兩個的差別:
一個 迭代器一定是可迭代對象 ,因為它一定有 __iter__ 方法。反過來則不成立。(事實上,Iterator 就是 Iterable 的子類)
迭代器的 __iter__ 方法 返回的是自身,并不產(chǎn)生新實例 。而可迭代對象的 __iter__ 方法通常會生成一個新的迭代器對象。
__iter__、__next__ 分別對應(yīng)于 Python 的內(nèi)置函數(shù) iter() 和 next():比如 iter(aList) 就相當于 aList.__iter__()。
所以關(guān)于上述兩點,我們可以有以下的例子來驗證:
迭代器和可迭代之間的繼承關(guān)系。
__iter__ 方法返回值的區(qū)別。id 相同代表是同一個實例。
明白了上述的概念之后,for 循環(huán)的實現(xiàn)就好理解了:
首先 for 循環(huán)會調(diào)用可迭代對象的 __iter__ 方法,獲取相應(yīng)的迭代器
每次循環(huán),將迭代器的 __next__ 方法的返回值賦值給循環(huán)變量
直到捕獲迭代器拋出的 StopIteration 異常,循環(huán)結(jié)束
再來看個例子:
思考題: 想一想為什么迭代器 aListIter 被 for 循環(huán)迭代第二次的時候就沒有輸出了?
既然 __next__ 方法可以自己定義,我們也可以自己實現(xiàn)一個迭代器。比如要 輸出一個斐波那契數(shù)列 (每一位數(shù)值都是前兩位數(shù)值之和,原題回復關(guān)鍵字 906 ),通常的做法是循環(huán),“高級”一點的做法是遞歸。但我們也可以直接寫一個斐波那契迭代器:
# 定義迭代器 class Fibonacci(): def __init__(self): self.a = 0 self.b = 1 def __iter__(self): return self def __next__(self): # 結(jié)束條件 if self.b > 100: raise StopIteration # 更新一次數(shù)值 self.a, self.b = self.b, self.a + self.b return self.a # 創(chuàng)建迭代器 fib = Fibonacci() # 進行迭代 for f in fib: print(f, end=" ")
輸出:
1 1 2 3 5 8 13 21 34 55 89
這個例子中,我們并沒有保存一個序列,只是定義了一種規(guī)則,就也可以被迭代。
使用迭代器的好處在于:它是一種 延遲操作 ,即當需要用到的時候才去產(chǎn)生結(jié)果。比如對于一個序列來說,如果我們要遍歷它,并不需要再一開始就把所有元素都生成好,而是只需要知道每個元素的下一個元素是什么就可以了。這樣可以節(jié)省很多空間,尤其對于數(shù)量很大的集合來說。
如果你不懂迭代器的概念,并不影響在代碼中使用 for 循環(huán)。但了解之后,你會對代碼理解得更透徹,同時這也是為我們后面要講到的 生成器 做鋪墊。
════
其他文章及回答:
如何自學Python | 新手引導 | 精選Python問答 | Python單詞表 | 人工智能 | 爬蟲 | 我用Python | requests | 計算機視覺 | 字符播放器 | 一圖學Python
歡迎搜索及關(guān)注公眾號: Crossin的編程教室
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/43200.html
摘要:簡評迭代器是惰性可迭代對象,函數(shù)在中是一個惰性的可迭代對象,那么是不是迭代器呢為什么。如果你不能將某些東西傳遞給函數(shù),那么它不是一個迭代器。的對象不是迭代器。 簡評:迭代器(iterator)是惰性可迭代對象(lazy iterable),range 函數(shù)在 Python 3 中是一個惰性的可迭代對象,那么 range 是不是迭代器呢?為什么。 TLNR:Python 3 中的 ran...
摘要:本文從使用對數(shù)組進行遍歷開始說起,粗略對比使用進行遍歷的差異,并由此引入中可迭代對象迭代器的概念,并對其進行粗略介紹。說到這里,就繼續(xù)說一下迭代器關(guān)閉的情況了。確實,符合可迭代協(xié)議和迭代器協(xié)議的。 本文從使用 forEach 對數(shù)組進行遍歷開始說起,粗略對比使用 forEach , for...in , for...of 進行遍歷的差異,并由此引入 ES6 中 可迭代對象/迭代器 的概...
摘要:本文重點掌握可迭代的對象的定義掌握可迭代對象迭代器與生成器之間的關(guān)系和異同熟悉標準庫中生成器。二迭代器迭代器介紹迭代器用于從集合中取出元素的對象。若想再次迭代須重建迭代器。迭代器檢查方式調(diào)用,。區(qū)別可迭代的對象不是迭代器。 導語:本文章記錄了本人在學習Python基礎(chǔ)之控制流程篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。 本文重點: 1、掌握可迭代的對象的...
摘要:通過生成器創(chuàng)建的迭代器也是可迭代對象,因為生成器默認會為屬性賦值。我們可以用來訪問對象的默認迭代器,例如對于一個數(shù)組獲得了數(shù)組這個可迭代對象的默認迭代器,并操作它遍歷了數(shù)組中的元素。 ES6 新的數(shù)組方法、集合、for-of 循環(huán)、展開運算符(...)甚至異步編程都依賴于迭代器(Iterator )實現(xiàn)。本文會詳解 ES6 的迭代器與生成器,并進一步挖掘可迭代對象的內(nèi)部原理與使用方法 ...
閱讀 3329·2021-11-16 11:45
閱讀 2673·2021-09-22 15:23
閱讀 577·2021-07-30 14:58
閱讀 474·2019-08-30 15:54
閱讀 2253·2019-08-29 16:19
閱讀 3030·2019-08-29 12:45
閱讀 957·2019-08-23 17:57
閱讀 1807·2019-08-23 17:54