迭代器(Iterable)和for..in..的三种协议

一。迭代器协议

  1.  迭代器协议:对象需要提供next方法,它要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代

  2. 可跌代对象:实现了迭代器协议的对象

  3. 协议是一种约定,可迭代对象实现迭代器协议,在Python中,迭代是通过for ... in来完成的

二。什么是可迭代对象

>>> from collections import Iterable
>>> class Fib:
...     def __iter__(self):
...             pass
... 
>>> a = Fib()
>>> isinstance(a,Iterable)
True
>>> 

  实现了__iter__方法的对象就是可迭代对象,a 就是可迭代对象。

三。什么是迭代器

>>> from collections import Iterable
>>> class Fib1:
...     def __init__(self):
...         self.a = 0
...     def next(self):
...         self.a = self.a + 1
...         if self.a > 4:
...             raise StopIteration()
...         return self.a
... 
>>> class Fib:
...     def __iter__(self):
...         return Fib1()
... 
>>> a = Fib()
>>> b = iter(a)
>>> b.next()
1
>>> b.next()
2
>>> b.next()
3
>>> b.next()
4
>>> b.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in next
StopIteration
>>> 

  a是可迭代对象,通过 iter(a) 让解析器调用a的 __iter__ 方法返回一个迭代器让 b 接收,b 就是一个迭代器对象,所以说,迭代器就是实现了 next 方法的对象。

  整合一下上面例子可得

>>> a = Fib()
>>> b = iter(a)
>>> while True:
...     try:
...         b.next()
...     except StopIteration:
...         break
... 
1
2
3
4
>>> 

  用循环调用 b 的 next 方法来迭代。

  再整合一下得

>>> a = Fib()
>>> for x in a:
...     print x
... 
1
2
3
4
>>> 

  可见,for...in 就是这样迭代可迭代对象的。

四。简单迭代器

   以斐波那契数列为例,写一个简单的迭代器

>>> from collections import Iterable
>>> class Fib:
...     def __init__(self):
...         self.a,self.b = 0,1
...     def __iter__(self):
...         return self
...     def next(self):
...         self.a,self.b = self.b,self.a + self.b
...         if self.a > 100:
...             raise StopIteration()
...         return self.a
... 
>>> a = Fib()
>>> for n in a:
...     print n
... 
1
1
2
3
5
8
13
21
34
55
89
>>> isinstance(a,Iterable)
True
>>> 

    Fib既是一个可迭代对象(因为它实现了__iter__方法),又是一个迭代器对象(因为实现了next方法)

   再简化一下,不用for....in....

>>> a = Fib()
>>> it = iter(a)                    // 解释器调用a的__iter__方法返回一个迭代器
>>> next(it)                        // 调用it的next方法
1
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> 

  一个迭代器只迭代一次,重复跌代要获得新的迭代器。

五。for...in... 协议

   1.   协议A: __iter__ + next

       这是迭代器的协议,和上面说的一样,for..in.. 先调用iter(a) 让a的__iter__返回一个迭代器,然后循环这个迭代器的next方法直到没有下一个元素异常退出。

       for...in... 首先执行跌达器,比如存在跌达和__getitem__就会以跌达器遍历.

   2.  协议B: __getitem__

>>> class B:
...     def __getitem__(self,n):
...         print n
...         time.sleep(2)
...         return 'a'
... 
>>> b = B()
>>> for x in b:
...     print x
... 
0
a
1
a
2
a
3
a
4

   n 一直循环的增长,直到有异常此循环才退出,一般作为下标索引遍历

>>> class B:
...     def __init__(self):
...         self.l = ['a','b','c','d','e']
...     def __getitem__(self,n):
...         return self.l[n]
... 
>>> b = B()
>>> for x in b:
...     print x
... 
a
b
c
d
e
>>> 

    3.  协议C: yield关键字

>>> def c():
...     yield 'a'
...     yield 'b'
...     yield 'c'
...     yield 'd'
... 
>>> c1 = c()
>>> print next(c1),next(c1),next(c1),next(c1),next(c1)
a b c d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> 

     用for..in来

>>> c1 = c()
>>> for x in c1:
...     print x
... 
a
b
c
d
>>> 

    c1是生成器(generator),是可迭代对象,当然也是迭代器对象,不是一次性列出结果,用到了才按照某种规则得出结果,占用内存很少,用for...in...时不断循环调用 next() 方法,每次 next() 后 yield 返回一个值并挂起,到下次 next() 从上次挂起的 yield 接着执行,yield 和 return 一样返回值,生成器只迭代一次。