Python之迭代器

>可迭代对象和迭代器傻傻分不清

之前自己一直没搞明白可迭代对象和迭代器的关系,总觉得两个没有区别,这次再来一探究竟

先来理解个概念

可迭代对象(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()方法的就是迭代器

你可能感兴趣的:(Python之迭代器)