迭代器(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 一样返回值,生成器只迭代一次。