迭代器Iterator
的特點
舉個生動例子:給馬場裏所有馬洗澡,確保每一匹馬都被洗到且只洗一次。
馬羣分別通過List
和Iterator
兩種形式,加載到for
循環中執行,我們對比看一下有什麼不同。
List
:
- 所有的馬抓到澡堂子裏關起來;(先算出所有的要循環的元素,一起加載到內存)
- 然後挨個洗澡;(順序執行)
- 都洗完了一起放出來。(執行期間所有元素都佔着內存)
Iterator
:
- 先不用管馬場裏有多少馬,確認馬場只出不進;(定義迭代器對象)
- 每次抓一匹馬出來洗澡然後放走;(
next()
取出一個元素執行,每次都是用到的時候纔去計算一個元素來,所以相比list幾乎不佔內存) - 直到沒馬可抓。(直到執行完畢)
迭代器的省內存、局部效率高的特點一目瞭然。
另外迭代器只能遍歷一次。
for i in List
執行完畢後可以馬上重複使用for i in List
再來一遍。而迭代器的for循環本質上還是next()
,因此在for i in Iterator
執行完畢後,Iterator
中已經沒有元素可輸出,需要重新定義迭代器,才能再執行for i in Iterator
輸出元素。
可迭代、迭代器、生成器區別
生成器是迭代器中的一種。
寫成數學表達的形式,大概可以理解爲:
可迭代Iterable
所有可以用for
循環的對象。
比如list
、tuple
、dict
、set
、str
、Iterator
、generator
。
>>> for i in 'ab':
print(i)
a
b
迭代器Iterator
可以被next()
函數調用並不斷返回下一個值的對象。
比如iter(list)
、iter(tuple)
、iter(dict)
、iter(set)
、iter(str)
、generator
。
>>> x = iter('ab')
>>> print(x)
<str_iterator object at 0x00000000025BA860>
>>> next(x)
a
注意:當next()
執行到直到沒有數據時,會拋出StopIteration
錯誤。
只不過通常我們都是通過for
循環來迭代它,並不需要關心StopIteration
的錯誤。
>>> for i in iter('ab'):
print(i)
a
b
生成器generator
同樣可以被next()
函數調用並不斷返回下一個值的對象。其實還是迭代器。
只不過是生成器是通過yield方法
、生成器表達式
產生的。
# 方法一:yield方法。如果一個函數定義中包含yield,那麼這個函數就由普通函數變成了生成器。
>>> def geti():
>>> for i in 'ab':
>>> yield i
>>> x = geti()
>>> print(x)
<generator object geti at 0x0000000003C08728>
# 方法二:生成器表達式。其實就是列表生成式的[]改成(),就創建了一個生成器。
>>> y = (i for i in 'ab')
>>> print(y)
<generator object <genexpr> at 0x0000000003C49200>
需要注意的是:遇到yield
回傳,下次執行,是從之前回傳斷開的地方繼續執行。
下面例子中可以看到:第二次使用next的時候,是先執行完了yield
後面的語句,才進入到下一個for
循環的。
>>> def geti():
>>> for i in 'ab':
>>> yield i
>>> print('is',i)
>>> x = geti()
>>> print(next(x))
a
>>> print(next(x))
is a
b