【Python】解析Python中的迭代器

目錄結構:html

contents structure [-]

 

 

 

 

在開始文章以前,先貼上一張Iterable、Iterator與Generator之間的關係圖:
python

1. Iterator VS Iterable

迭代器(Iterator)

迭代器是實現了迭代器協議的類對象,迭代器協議規定了迭代器類必需定義__next()__方法。當對迭代器對象調用next()方法時,對象會去調用__next()__計算迭代器的返回值。數據結構

 

可迭代對象(Iterable)

可迭代對象能夠是任何對象,不必定是能返回迭代器的數據結構。一個可迭代對象會直接或間接性的調用這兩個方法__iter()__和__next()__;其中__iter()__方法只能返回迭代器對象,__next()__則供給迭代器進行調用。

一般狀況下,可迭代類都會實現__iter()__和__next()__,而且__iter()__返回它本身,換句話說,該類便是迭代器又是可迭代類。

下面的代碼展現了迭代器和可迭代器對象之間的差異:app

a_set = {1, 2, 3}#定義set數據類型,set是可迭代類型
b_iterator = iter(a_set)#獲得set的迭代器
#Output: 1
print(next(b_iterator))

#Output: <class 'set'>
print(type(a_set))

#Output: <class 'set_iterator'>
print(type(b_iterator))

從結果能夠看出a_set是一個可迭代類型(set類型),b_iterator是一個迭代器(set_iterator),它們兩個是徹底不一同的類型。

下面的自定義了一個迭代器:函數

class Series(object):
    def __init__(self, low, high):
        self.current = low
        self.high = high

    def __iter__(self):
        return self

    def __next__(self):
        if self.current > self.high:
            raise StopIteration
        else:
            self.current += 1
            return self.current - 1

n_list = Series(1,10)    
print(list(n_list))

從上面的代碼能夠看出,__iter__返回了迭代器自己。__next__返回迭代器的下一個值,若是沒有下一個返回值那麼會拋出StopIteration異常。若是沒有在合適的位置拋出StopIteration異常結束迭代,那麼在某些循環語句中(例如:for loop),將會造成死循環,因此在__next__中必須要在合適位置添加退出語句(拋出StopIterator異常)。oop

 

2.Itertools 模塊

Itertools是Python的內置模塊,其中包含了可以建立迭代器的函數。簡而言之,它提供了許多可以與迭代器交互的方法。
下面是咱們使用Itertools模塊中count函數的案例:spa

from itertools import count
sequence = count(start=0, step=1)
while(next(sequence) <= 10):
    print(next(sequence),end=" ")

輸出:code

1 3 5 7 9 11 


Itertools中的cycle函數能夠建立無限迭代器,例如:htm

from itertools import cycle
dessert = cycle(['Icecream','Cake'])
count = 0
while(count != 4):
    print('Q. What do we have for dessert? A: ' + next(dessert))
    count+=1

輸出:對象

Q. What do we have for dessert? A: Icecream
Q. What do we have for dessert? A: Cake
Q. What do we have for dessert? A: Icecream
Q. What do we have for dessert? A: Cake


關於更多itertools模塊的使用,能夠參見python文檔

 

3.生成器(Generator)

生成器能夠說是迭代器的親兄弟,生成器容許咱們像上面那樣寫迭代器而不用額外定義__iter__()和__next__()方法。

看下面的案例:

def series_generator(low, high):
    while low <= high:
       yield low
       low += 1

n_list = []
for num in series_generator(1,10):
    n_list.append(num)

print(n_list)

若是一個方法中出現了yield關鍵字,那麼該方法就是一個生成器。生成器中沒有return語句,函數的返回值其實是一個generator。當循環開始執行到yield語句後,low的值會被擴展到要返回的generator中。當下一次循環再次到達yield語句時,generator會從上一次中止的地方恢復執行,而且將最新的low值添加到generator中。這樣一種循環,直到low>high退出循環。

生成器支持延遲計算,只有當去取生成器中的值時纔會執行生成器的函數體。
例如:

def test():
    print("進入test函數")
    for i in range(2):
        print("yield number ",i)
        yield i
if "__main__" == __name__:
    print("開始調用test")
    res =  test()
    print("結束調用test")
    next(res)
    next(res)

輸出:

開始調用test
結束調用test
第一次next(res)
進入test函數
yield number 0
第二次next(res)
yield number  1

從結果能夠看出,只有使用next調用迭代器時(使用for,while循環也能夠),纔會去執行生成器函數中的內容。

python中生成器能夠分爲生成器函數和生成器表達式,這兩種類型的表現形式徹底不一樣。
生成器函數是一個函數體中有yield關鍵字的,咱們上面定義的test就是生成器函數。
生成器表達式的使用比較受限制,一個生成器表達式返回一個生成器。下面是一個使用生成器表達式的案例:

squares = (x * x for x in range(1,10))
print(type(squares))
print(list(squares))

輸出:

<class 'generator'>
[1, 4, 9, 16, 25, 36, 49, 64, 81]


生成器的效率是很是高的,生成器能夠更好的利用內存和CPU的使用效率,而且一般生成器的代碼都比較少,這使用生成器的代碼很是好容易理解。應此應該儘可能多的在代碼中使用生成器

參考文檔
https://www.datacamp.com/community/tutorials/python-iterator-tutorial

相關文章
相關標籤/搜索