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函数获取迭代器,之后对迭代器进行迭代

posted @ 2019-06-10 21:51  luoheng  阅读(487)  评论(0编辑  收藏  举报