>可迭代对象和迭代器傻傻分不清
之前自己一直没搞明白可迭代对象和迭代器的关系,总觉得两个没有区别,这次再来一探究竟
先来理解个概念
可迭代对象(iterable)是可以迭代的任何东西,迭代器(iterator)是执行实际迭代的东西
>可迭代对象
让我们从熟悉的数据类型说起吧
In [1]: iter([1,2,3])
Out[1]:
In [2]: iter((1,2,3))
Out[2]:
In [3]: iter("hello word")
Out[3]:
In [5]: iter(1)
TypeError: 'int' object is not iterable
看Out输出的内容,TypeError: 'int' object is not iterable,这句话的意思就是int类型不是一个可迭代对象,那为何上面的list/tuple/str没有报错呢?难道它们就是可迭代对象?这三种数据类型经过iter()方法后返回iterator迭代器?为什么呢...
为了验证我们的猜想,使用isinstance()来做个了结
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
经过我们的验证,list/tuple/str 是可迭代对象,int就不是,那list/tuple/str和int有什么区别呢?
细心的你发现,可迭代对象都是可以用for循环遍历的?而int就不可以,真的是这样吗?for循环和可迭代对象有关系吗?不急,我们再来验证下...
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循环时,报出错误TypeError: 'int' object is not iterable,其它的就没有,难道for循环的条件也是需要一个可迭代对象?
废话这么多,那什么是可迭代对象呢?下面可要画重点了数据类型实现了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)
in
----> 1 for i in mylist:
2 print(i)
3
TypeError: 'Mylist' object is not iterable
有结论吗?不急不急,再来看一个
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)
in
----> 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
仔细的观众已经看出了猫腻,一个数据类型是否是可迭代对象关系到它是否实现了iter方法,至此,关于可迭代对象已经说明白了
那迭代器呢?细心的观众又发现了,在我们用for循环遍历mylist时,报出了错误TypeError: iter() returned non-iterator of type 'NoneType',到此,我们可以知道,for循环遍历的过程中,调用了iter()方法报出了return non-iterator,说iter()返回的不是一个迭代器,龟龟,这就把迭代器引出来了,既然出来了,那就看看吧!
我们在Mylist类中,实现了iter方法,但是没有具体的实现,当我们使用for循环时,并没有报出'Mylist' object is not iterable的错误,那我们就可以推断Mylist是一个可迭代对象,但接下来却报出了return non-iterator,说明for循环遍历时需要一个迭代器,而这个迭代器是iter()方法返回的,至此,我们可以得到一个结论,迭代器是可迭代对象;那什么又是迭代器呢?
我们将目光转移到文章的开始
In [1]: iter([1,2,3])
Out[1]:
In [2]: iter((1,2,3))
Out[2]:
In [3]: iter("hello word")
Out[3]:
In [5]: iter(1)
TypeError: 'int' object is not iterable
我们对list/tuple/str数据类型使用iter方法时,返回的结果时**_iterator,这是一个迭代器,我们对比Mylist这个类,它是一个可跌代对象,iter()返回的却不是一个迭代器,那这个迭代器就是这个iter()方法返回的?那iter()内部需要怎么实现呢?
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)
in
----> 1 next(it)
StopIteration:
每次调用next()都返回一个值,这个和for的遍历是不是相同呢?还记得我们在Mylist类中使用for遍历它的实例,返回TypeError: iter() returned non-iterator of type 'NoneType',说iter()返回的不是迭代器。再结合上面和for循环对字符串的遍历,是否next()就是实现迭代器的关键呢?那就来试试
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]:
我们发现可以使用for循环遍历数据了,我们来做一个斐波那契数列的迭代器
In [54]: class FibIterator(object):
...: """斐波那契数列迭代器"""
...: def __init__(self, n):
...: """
...: :param n: int, 指明生成数列的前n个数
...: """
...: self.n = n
...: # current用来保存当前生成到数列中的第几个数了
...: self.current = 0
...: # num1用来保存前前一个数,初始值为数列中的第一个数0
...: self.num1 = 0
...: # num2用来保存前一个数,初始值为数列中的第二个数1
...: self.num2 = 1
...:
...: def __next__(self):
...: """被next()函数调用来获取下一个数"""
...: 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
至此,我们来总结下可迭代对象和迭代器
实现了iter()方法的就是可迭代对象;实现了Iter()和next()方法的就是迭代器