>可迭代對象和迭代器傻傻分不清
之前自己一直沒搞明白可迭代對象和迭代器的關(guān)系纽匙,總覺得兩個沒有區(qū)別,這次再來一探究竟
先來理解個概念
可迭代對象(iterable)是可以迭代的任何東西绰更,迭代器(iterator)是執(zhí)行實際迭代的東西
>可迭代對象
讓我們從熟悉的數(shù)據(jù)類型說起吧
In [1]: iter([1,2,3])
Out[1]: <list_iterator at 0x7fd6a01650f0>
In [2]: iter((1,2,3))
Out[2]: <tuple_iterator at 0x7fd6a0b57860>
In [3]: iter("hello word")
Out[3]: <str_iterator at 0x7fd6a0b57be0>
In [5]: iter(1)
TypeError: 'int' object is not iterable
看Out輸出的內(nèi)容,TypeError: 'int' object is not iterable,這句話的意思就是int類型不是一個可迭代對象燎猛,那為何上面的list/tuple/str沒有報錯呢?難道它們就是可迭代對象溉瓶?這三種數(shù)據(jù)類型經(jīng)過iter()方法后返回iterator迭代器急鳄?為什么呢...
為了驗證我們的猜想谤民,使用isinstance()來做個了結(jié)
In [17]: from collections import Iterable
In [19]: isinstance([1,2,3], Iterable)
Out[19]: True
In [20]: isinstance((1,2,3), Iterable)
Out[20]: True
In [21]: isinstance("hello word", Iterable)
Out[21]: True
In [22]: isinstance(1, Iterable)
Out[22]: False
經(jīng)過我們的驗證,list/tuple/str 是可迭代對象疾宏,int就不是张足,那list/tuple/str和int有什么區(qū)別呢?
細心的你發(fā)現(xiàn)坎藐,可迭代對象都是可以用for循環(huán)遍歷的为牍?而int就不可以,真的是這樣嗎岩馍?for循環(huán)和可迭代對象有關(guān)系嗎碉咆?不急,我們再來驗證下...
In [23]: for i in [1,2,3]:
...: print(i)
...:
1
2
3
In [24]: for i in (1,2,3):
...: print(i)
...:
1
2
3
In [25]: for i in "hello":
...: print(i)
...:
h
e
l
l
o
In [27]: for i in 1:
...: print(i)
...:
TypeError: 'int' object is not iterable
過不奇然蛀恩,和我們猜想的一致疫铜,當我們對1使用for循環(huán)時,報出錯誤TypeError: 'int' object is not iterable双谆,其它的就沒有壳咕,難道for循環(huán)的條件也是需要一個可迭代對象?
廢話這么多顽馋,那什么是可迭代對象呢谓厘?下面可要畫重點了數(shù)據(jù)類型實現(xiàn)了iter方法的就是一個可迭代對象,那我們順著這個線索去驗證下,不能你說對就對寸谜,一起來看看吧竟稳!
In [29]: class Mylist(object):
...: def __init__(self):
...: self.container = []
...: def add(self, item):
...: self.container.append(item)
...:
In [30]: mylist = Mylist()
In [31]: mylist.add(1)
In [32]: mylist.add(2)
In [33]: for i in mylist:
...: print(i)
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-33-082208dcc545> in <module>
----> 1 for i in mylist:
2 print(i)
3
TypeError: 'Mylist' object is not iterable
有結(jié)論嗎?不急不急程帕,再來看一個
In [35]: class Mylist(object):
...: def __init__(self):
...: self.container = []
...: def add(self, item):
...: self.container.append(item)
...: def __iter__(self):
...: pass
...:
In [36]: mylist = Mylist()
In [37]: mylist.add(1)
In [38]: mylist.add(2)
In [39]: for i in mylist:
...: print(i)
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-39-082208dcc545> in <module>
----> 1 for i in mylist:
2 print(i)
3
TypeError: iter() returned non-iterator of type 'NoneType'
In [40]: from collections import Iterable
In [41]: isinstance(mylist, Iterable)
Out[41]: True
仔細的觀眾已經(jīng)看出了貓膩束亏,一個數(shù)據(jù)類型是否是可迭代對象關(guān)系到它是否實現(xiàn)了iter方法,至此靴庆,關(guān)于可迭代對象已經(jīng)說明白了
那迭代器呢匣摘?細心的觀眾又發(fā)現(xiàn)了,在我們用for循環(huán)遍歷mylist時岭埠,報出了錯誤TypeError: iter() returned non-iterator of type 'NoneType'盏混,到此,我們可以知道惜论,for循環(huán)遍歷的過程中许赃,調(diào)用了iter()方法報出了return non-iterator,說iter()返回的不是一個迭代器,龜龜馆类,這就把迭代器引出來了混聊,既然出來了,那就看看吧乾巧!
我們在Mylist類中句喜,實現(xiàn)了iter方法预愤,但是沒有具體的實現(xiàn),當我們使用for循環(huán)時咳胃,并沒有報出'Mylist' object is not iterable的錯誤植康,那我們就可以推斷Mylist是一個可迭代對象,但接下來卻報出了return non-iterator展懈,說明for循環(huán)遍歷時需要一個迭代器销睁,而這個迭代器是iter()方法返回的,至此存崖,我們可以得到一個結(jié)論冻记,迭代器是可迭代對象;那什么又是迭代器呢金句?
我們將目光轉(zhuǎn)移到文章的開始
In [1]: iter([1,2,3])
Out[1]: <list_iterator at 0x7fd6a01650f0>
In [2]: iter((1,2,3))
Out[2]: <tuple_iterator at 0x7fd6a0b57860>
In [3]: iter("hello word")
Out[3]: <str_iterator at 0x7fd6a0b57be0>
In [5]: iter(1)
TypeError: 'int' object is not iterable
我們對list/tuple/str數(shù)據(jù)類型使用iter方法時,返回的結(jié)果時**_iterator,這是一個迭代器贞瞒,我們對比Mylist這個類趁曼,它是一個可跌代對象军浆,iter()返回的卻不是一個迭代器,那這個迭代器就是這個iter()方法返回的挡闰?那iter()內(nèi)部需要怎么實現(xiàn)呢?
In [2]: from collections import Iterator
In [3]: isinstance([1,2,3], Iterator)
Out[3]: False
In [4]: isinstance(iter([1,2,3]), Iterator)
Out[4]: True
In [5]: isinstance("hello", Iterator)
Out[5]: False
In [6]: isinstance(iter("hello"), Iterator)
Out[6]: True
接下來再看個例子
In [22]: it = iter("hello")
In [23]: next(it)
Out[23]: 'h'
In [24]: next(it)
Out[24]: 'e'
In [25]: next(it)
Out[25]: 'l'
In [26]: next(it)
Out[26]: 'l'
In [27]: next(it)
Out[27]: 'o'
In [28]: next(it)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-28-bc1ab118995a> in <module>
----> 1 next(it)
StopIteration:
每次調(diào)用next()都返回一個值赞季,這個和for的遍歷是不是相同呢?還記得我們在Mylist類中使用for遍歷它的實例奢驯,返回TypeError: iter() returned non-iterator of type 'NoneType'申钩,說iter()返回的不是迭代器。再結(jié)合上面和for循環(huán)對字符串的遍歷撒遣,是否next()就是實現(xiàn)迭代器的關(guān)鍵呢管跺?那就來試試
In [38]: class Mylist(object):
...: def __init__(self):
...: self.container = []
...: def add(self, item):
...: self.container.append(item)
...: def __iter__(self):
...: myiterator = MyIterator(self)
...: return myiterator
...:
In [39]: class MyIterator(object):
...: def __init__(self,mylist):
...: self.mylist = mylist
...: self.current = 0
...: def __next__(self):
...: if self.current < len(self.mylist.container):
...: item = self.mylist.container[self.current]
...: self.current += 1
...: return item
...: else:
...: raise StopIteration
...: def __iter__(self):
...: return self
...:
In [40]: mylist = Mylist()
In [41]: mylist.add(1)
In [42]: mylist.add(2)
In [43]: mylist.add(3)
In [44]: mylist.add(4)
In [45]: mylist.add(5)
In [46]: for i in mylist:
...: print(i)
...:
1
2
3
4
5
In [47]:
我們發(fā)現(xiàn)可以使用for循環(huán)遍歷數(shù)據(jù)了,我們來做一個斐波那契數(shù)列的迭代器
In [54]: class FibIterator(object):
...: """斐波那契數(shù)列迭代器"""
...: def __init__(self, n):
...: """
...: :param n: int, 指明生成數(shù)列的前n個數(shù)
...: """
...: self.n = n
...: # current用來保存當前生成到數(shù)列中的第幾個數(shù)了
...: self.current = 0
...: # num1用來保存前前一個數(shù),初始值為數(shù)列中的第一個數(shù)0
...: self.num1 = 0
...: # num2用來保存前一個數(shù)廉涕,初始值為數(shù)列中的第二個數(shù)1
...: self.num2 = 1
...:
...: def __next__(self):
...: """被next()函數(shù)調(diào)用來獲取下一個數(shù)"""
...: if self.current < self.n:
...: num = self.num1
...: self.num1, self.num2 = self.num2, self.num1+self.num2
...: self.current += 1
...: return num
...: else:
...: raise StopIteration
...:
...: def __iter__(self):
...: """迭代器的__iter__返回自身即可"""
...: return self
...:
In [55]: fb = FibIterator(10)
In [56]: next(fb)
Out[56]: 0
In [57]: next(fb)
Out[57]: 1
In [58]: next(fb)
Out[58]: 1
In [59]: for i in fb:
...: print(i)
...:
2
3
5
8
13
21
34
至此,我們來總結(jié)下可迭代對象和迭代器
實現(xiàn)了iter()方法的就是可迭代對象火的;實現(xiàn)了Iter()和next()方法的就是迭代器