轉載請注明出處:http://www.itdecent.cn/u/5e6f798c903a
[^*] 表示注腳,在文末可以查看對應連接,但簡書不支持該語法。
迭代器是表示數(shù)據(jù)流的對象。
迭代器對象自身需要支持以下兩個方法,這兩個共同構成了迭代器協(xié)議:[^7]
-
iterator.__iter__()返回迭代器對象本身。由于實現(xiàn)了
__iter__對象都是屬于 IterableObjc ,因此迭代器也屬于 IterableObjc;并且在其它接受 IterableObjc 的地方,也多半可以接受迭代器。 -
iterator.__next__()返迭代器中的下一個項。重復調用迭代器的
__next__()方法(或通過內置函數(shù)next()重復調用迭代器),將返回流中連續(xù)的項。當沒有再無數(shù)據(jù)可供使用時,便會拋出StopIteration異常,這時表明該迭代器對象已經(jīng)耗盡,若此后仍試圖調用該迭代器的__next__()方法,將會再次拋出StopIteration異常。[^4]一旦迭代器的
__next__()方法拋出StopIteration,則必須在后續(xù)調用中繼續(xù)拋出異常。不遵從此特性的實現(xiàn)被視為不正確。[^7]
如果容器支持不同類型的迭代,則可以提供額外的方法來專門請求這些迭代類型的迭代器(支持多種迭代形式的對象的一個例子是樹結構,它支持 breadth-first 和 depth-first 兩種遍歷方式)。[^7]
Python 定義了多個迭代器對象,以支持對如下類型進行迭代:常規(guī)(general)序列類型和特殊(specific)序列類型、字典以及其它專業(yè)表單(specialized forms)。除迭代器協(xié)議的實現(xiàn)之外,其實特定類型并不重要。[^7]
1. 迭代器與 for 循環(huán)
將迭代器用于 for 循環(huán)時,for 循環(huán)仍會調用 iter() 來處理迭代器對象,然后通過 next() 逐一獲取每個元素,直至 __next__ 拋出 StopIteration 為止。注意:將某個迭代器對象傳遞給 iter() 后,只會返回指向該迭代器的引用,并不會創(chuàng)建具備新id的迭代器對象。
>>> aa = [1,2,3,]
>>> bb = iter(aa)
>>> bb
<list_iterator object at 0x000001B393436E48>
>>> cc = iter(bb)
>>> cc # bb和cc引用同一個對象
<list_iterator object at 0x000001B393436E48>
通常情況下,如果反復嘗試將某個迭代器用于 for 循環(huán),其實在第一次循環(huán)結束時就會耗盡該迭代器,之后只會反復使用這個已被耗盡的迭代器,看起來如同在使用一個空容器。[^4]
>>> aa = [1,2,3,]
>>> bb = iter(aa)
>>> for i in bb:
print(i)
1
2
3
>>> for i in bb:
print(i)
>>>
但是,如果在__iter__ 中重置相關變量,則可讓迭代器反復用于for循環(huán),并且每次都有輸出。
class IteratorObjc:
def __iter__(self):
self._count = 0
return self
def __next__(self):
while self._count < 3:
self._count += 1
return self._count
class IteratorObjc:
"""
在這種情況下,每次調用__iter__方法時,
會返回實例對象自身,不會創(chuàng)建具備新id的迭代器對象。
"""
def __iter__(self):
# 重置_count,便可反復進行迭代
self._count = 0
# 調用時返回實例自身
return self
def __next__(self):
while self._count < 3:
self._count += 1
return self._count
a_iterator = IterableObjc()
for i in a_iterator:
print(i, end=',')
print()
for i in a_iterator:
print(i, end=',')
2. 迭代器與內置函數(shù)
由于迭代器也屬于 IterableObjc,所以迭代器也可直接用于如下內置函數(shù):
any(iterable)class list([iterable])map(function, iterable, ...)- ....
通常情況下,如果反復將某個迭代器傳遞給內置函數(shù)。在第一次使用該迭代器時就會耗盡該迭代器,之后只會反復使用這個已被耗盡的迭代器,看起來如同在使用一個空容器。
>>> aa = [1,2,3,]
>>> bb = iter(aa)
>>> list(bb)
[1, 2, 3]
>>> list(bb)
[]
但是,如果在__iter__ 中重置相關變量,則可讓迭代器反復用于內置函數(shù)。
class IteratorObjc:
def __iter__(self):
self._count = 0
return self
def __next__(self):
while self._count < 3:
self._count += 1
return self._count
a_iterator = IterableObjc()
print(list(a_iterator))
print(list(a_iterator))
輸出
[1, 2, 3]
[1, 2, 3]
3. itertools
10.1.
itertools— Functions creating iterators for efficient looping
itertools 模塊提供了眾多用于創(chuàng)建迭代器的函數(shù)。下面簡要介紹幾個:
-
count()函數(shù)返回的迭代器可產生一串連續(xù)的整數(shù),并且通過該迭代器可產生無限個整數(shù)。與內置函數(shù)range()不同,count()不需要通過參數(shù)來設定上線。>>> from itertools import count >>> counter = count(start=10) >>> next(counter) 10 >>> next(counter) 11 -
cycle()函數(shù)會把所接受的可迭代對象轉換為一個無限循環(huán)的迭代器。>>> from itertools import cycle >>> colors = cycle(['red', 'white', 'blue']) >>> next(colors) 'red' >>> next(colors) 'white' >>> next(colors) 'blue' >>> next(colors) 'red' -
islice()函數(shù)會截取輸入迭代器的一部分,并把這部分作為輸出迭代器返回>>> from itertools import islice >>> colors = cycle(['red', 'white', 'blue']) # infinite >>> limited = islice(colors, 0, 4) # finite >>> for x in limited: # so safe to use for-loop on ... print(x) red white blue red
注腳:
[1] 語言參考 - 3.1. Objects, values and types
[2] 標準庫 8.4. collections.abc — Abstract Base Classes for Containers
[3] Iterables vs. Iterators vs. Generators | 完全理解 Python 迭代對象、迭代器、生成器
[4] Glossary 術語表
[5] iter(object[, sentinel])
[6] 語言參考 - 8.3. The for statement
[7] 標準庫 - 4.5. terator Types
[8] 語言參考 - 3.3.7. Emulating container types
[9] 語言參考 -3.2. The standard type hierarchy