淺析python迭代器

可迭代對象Iterable

可迭代對象是什么?簡單點說,那些能被for循環的對象就是可迭代對象。精確一點來說可迭代對象是指有iter( )方法來返回一個迭代器的對象。而for循環就只能用于這些對象上。(什么是迭代器?我們等一下來講)
典型的可迭代對象包括String,list,dict,set等。for循環的過程本身就是迭代過程。
通過isinstance()來判斷某個實體是否是可迭代對象。

from collections import Iterable
from collections import Iterator

x = {1,2,3}#x是一個set
for i in x:
    print(i)
1
2
3
isinstance(x,Iterable)
True

迭代器Iterator

可被迭代對象為何可以使用for循環呢?這是因為在這些對象里面都有隱藏函數iter( )來獲取其迭代器。
凡是有iter( )方法的對象都是可迭代對象Iterable。例如我們可以隨便自己定義一個Iterable對象。

class it(object):
    def __iter__(self):
        pass
i = it()
isinstance(i,Iterable)
True

那么什么是迭代器(Iterator)呢?從本質上來說,凡是同時有iter( )和next( )方法的都是迭代器。注意,一般來說Iterable的iter( )方法會返回它的迭代器,而迭代器的iter( )方法則會直接返回它自身。
迭代器的核心就在于next( )方法,有了這個方法的對象可以通過內建函數next()來迭代得到下一個值。
以最簡單的list來舉例子:

x = list(range(20))#x是一個可迭代對象Iterable
it = iter(x)#it是x的迭代器Iterator
print(next(it))
print(next(it))
print(next(it))
0
1
2

因此我們也可以揭開python中for循環的本質了,for循環之所以能夠作用于Iterable類型的對象,是因為for循環本身等價于取該對象的迭代器,然后不停的next()直到結束。

for i in range(20):
    XXX#執行循環內容

等價于:

tempi = iter(range(20))
i = next(tempi)
XXX#執行循環內容
i = next(tempi)
XXX#執行循環內容
i = next(tempi)
XXX#執行循環內容
...
...
#直到next函數結束

因此我們也可以自己寫一個Iterable對象,并用for循環作用于它。比如我們想寫一個能夠被for循環輸出斐波那契數列的類:

class fib(object):
    def __init__(self,n=20):
        self.n = n
    def __iter__(self):
        return fibiter(self.n)

class fibiter(object):
    def __init__(self,n):
        self.max = n
        self.a = 0
        self.b = 1
    def __iter__(self):
        return self
    def __next__(self):
        while(self.b<self.max):
            temp = self.a+self.b
            self.a = self.b
            self.b = temp
            return self.a
        raise StopIteration #很重要,必須要拋出StopIteration異常,不然for循環將不會終止

for i in fib():
    print(i)
1
1
2
3
5
8
13

上面的程序中,fib類創建的對象是可迭代對象Iterable,因為它有iter( )方法來返回一個迭代器fibiter。而fibiter則是一個典型的迭代器Iterator,通過next方法來不斷的迭代出下一個值。因此我們可以通過for循環來訪問fib類的對象。

不過值得注意的是我們也可以直接通過for循環來訪問一個Iterator,這是因為python強制規定了作為一個Iterator,除了要有next( )方法之外,還要有iter( )方法。那么就很容易理解了,Iterator的iter( )方法一般返回的是自身。因此當for循環作用于Iterator對象的時候,首先會用iter()方法返回自己本身,然后再調用next方法取下一個值。

這樣就方便了我們使用Iterator的時候,不用一個個的next來取值,可以直接用for循環。
那么就有人問了,這樣的Iterator本質上豈不是就是一個Iterable嗎?答案是:沒錯,就是這樣。

it = iter(fib())
print(isinstance(it,Iterator),isinstance(it,Iterable))
True True

因此有時候為了簡單,不將可迭代對象和他的迭代器拆開,直接將二者合二為一寫成一個即是Iterable也是Iterator的可迭代對象(也可以稱為迭代器)。例如剛才的fib數列類可以改成:

class fib_1(object):
    def __init__(self,n=20):
        self.n = n
        self.a = 0
        self.b = 1
    def __iter__(self):
        return self
    def __next__(self):
        while(self.b<=self.n):
            temp = self.a+self.b
            self.a = self.b
            self.b = temp
            return self.a
        raise StopIteration
        
for i in fib_1(30):
    print(i)
1
1
2
3
5
8
13
21
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容