python tips:迭代器与可迭代对象
for循环
1 for i in s: 2 print(i)
在上述for循环中,不断地将s中的值赋值给i,然后打印出来。这种只针对s中元素的循环称为对s的迭代,能够迭代的s称为可迭代的。
python为了实现for循环,需要迭代的对象实现迭代协议或序列协议,以获取一个迭代器。下面只讨论迭代协议,即实现一个预定义的方法:
1 __iter__(self):返回一个迭代器
for在对对象进行迭代时,会调用对象的__iter__方法构造一个迭代器,然后对该迭代器进行迭代,迭代过程就是不断调用迭代器的方法获取元素:
1 __next__(self):返回下一个元素,迭代完成抛出stopIteration异常
定义上,实现了上述两个方法的对象称作迭代器。
从理论上讲__iter__方法只要返回一个包含__next__方法的对象就行了,不一定要是迭代器。
这里需要区分迭代器和可迭代对象,迭代器是实现了__iter__和__next__方法的对象,它一定是可迭代对象。而可迭代对象不一定是迭代器,实现了__iter__方法就是可迭代对象。
列表、元组、字符串、字典等对象只实现了__iter__方法,所以它们是可迭代对象,而不是迭代器。
列表不是迭代器
1 class A: 2 def __iter__(self): 3 return [1, 2, 3, 4, 5] 4 5 class B: 6 def __iter__(self): 7 return [1, 2, 3, 4, 5].__iter__() 8 9 try: 10 for a in A(): 11 print(a) 12 except Exception as e: 13 print(e) 14 15 for b in B(): 16 print(b)
输出结果
1 iter() returned non-iterator of type 'list' 2 1 3 2 4 3 5 4 6 5
__iter__方法一定要返回迭代器,而列表虽然是可迭代对象,但不是迭代器,所以会抛出异常。显式调用列表的__iter__方法返回一个迭代器即可正常运行。
__iter__返回的对象实现了__next__就可以正常迭代
1 class A: 2 def __iter__(self): 3 return B() 4 5 class B: 6 def __init__(self): 7 self.i = 0 8 self.n = 5 9 def __next__(self): 10 if self.i < self.n: 11 self.i += 1 12 return self.i 13 raise StopIteration 14 15 for i in A(): 16 print(i)
输出结果
1 1 2 2 3 3 4 4 5 5
for循环对A的实例进行迭代,__iter__返回了B的实例,它没有__iter__方法,所以不是迭代器,但是可以正常迭代。
使用序列协议的for循环
1 class A: 2 def __init__(self): 3 self.array = [1, 2, 3, 4, 5] 4 5 def __getitem__(self, i): 6 return self.array[i] 7 8 for i in A(): 9 print(i)
输出结果
1 1 2 2 3 3 4 4 5 5
上述代码实现序号从0开始的__getitem__方法,即实现了序列协议,于是for循环能够从实现序列协议的对象中构造一个迭代器用于迭代。
for循环获取迭代器的本质是通过内建函数iter,它能够将实现了迭代器协议(主要是__iter__方法)或者序列协议(__getitem__,序号从0开始)的对象转换成生成器。在两种协议都存在的情况下,以迭代器协议为准。
总结:
1. 迭代器是实现了__iter__和__next__方法的对象,可迭代对象实现了__iter__或者实现了序列协议,可在for中进行迭代。列表等对象不是迭代器
2. for循环利用iter函数获取迭代器,之后对迭代器进行迭代