迭代器-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
对象,但list
、dict
、str
虽然是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对象。