迭代器-Iterator

可以直接作用于for循环的数据类型有以下两类

一类是基础数据类型里的str,list,tuple,dict,set

另一类是generator

这些可以直接作用于for循环的对象统称为可迭代对象 Iterable 

可以使用isinstance()判断一个对象是否是Iterable对象:

 1 from collections import Iterable
 2 
 3 
 4 def test_yield():
 5     yield 1
 6     yield 2
 7 
 8 print(type([]), isinstance([], Iterable))
 9 print(type(()), isinstance((), Iterable))
10 print(type('abc'), isinstance('abc', Iterable))
11 print(type({}), isinstance({}, Iterable))
12 print(type(100), isinstance(100, Iterable))
13 result = test_yield()
14 print(type(result), isinstance(result, Iterable))

以下是结果:

1 <class 'list'> True
2 <class 'tuple'> True
3 <class 'str'> True
4 <class 'dict'> True
5 <class 'int'> False
6 <class 'generator'> True

 

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

可以被next()函数调用并不断返回下一个值的对象称为迭代器 Iterator 。

可以使用isinstance()判断一个对象是否是Iterator对象:

1 print(isinstance((x for x in range(10)),Iterator))
2 print(type(result), isinstance(result, Iterator))
3 print(type([]), isinstance([], Iterator))

以下是运行结果:

1 True
2 <class 'generator'> True
3 <class 'list'> False

从上面的结果看,生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

可以使用内置函数iter()将list,dict,str,tuple等转化成Iterator print(type(iter([])), isinstance(iter([]), Iterator)) 

 

那为什么list,tuple,dict,str是Iterable,却不是Iterator呢?

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Python的for循环本质上就是通过不断调用next()函数实现的,

例如对于 number_list = [1, 2, 3, 4, 5] ,下面两段代码是等价的:

1 for item in number_list:
2     print(item)
1 it = iter(number_list)
2 while True:
3     try:
4         number = next(it)
5         print(number)
6     except StopIteration:
7         break

 但是我们如果对number_list使用next()方法却会报错:

1 next(number_list)
2 TypeError: 'list' object is not an iterator

 

代理迭代

假如我们自定义了一个类,我想直接在这个类的对象进行上执行迭代操作:

1 class Node(object):
2     def __init__(self, value):
3         self.__value = value
4         self.__children = []

实际上我们只需要定义一个 __iter__(self) 方法,将迭代操作代理到类内部的可转化为迭代器的字段上去:

 1 class Node(object):
 2     def __init__(self, value):
 3         self.__value = value
 4         self.__children = []
 5 
 6     def add_child(self, node):
 7         self.__children.append(node)
 8 
 9     def set_value(self, value):
10         self.__value = value
11 
12     def get_value(self):
13         return self.__value
14 
15     def __iter__(self):  # __iter__() 方法只是简单的将迭代请求传递给内部的__children    
16         return iter(self.__children)

探讨:

Python 的迭代器协议需要__iter__() 方法返回一个实现了__next__() 方法的迭代
器对象。如果你只是迭代遍历其他容器的内容,你无须担心底层是怎样实现的。你所
要做的只是传递迭代请求既可。
这里的iter() 函数的使用简化了代码,iter(s) 只是简单的通过调用
s.__iter__()方法来返回对应的迭代器对象,就跟len(s) 会调用s.__len__()原理
是一样的。

 

小结

-凡是可作用于for循环的对象都是Iterable类型;

-凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

-集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

posted on 2017-02-06 15:44  _Joshua  阅读(309)  评论(0编辑  收藏  举报

导航