可以直接作用于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))
以下是结果:
1True2 True3 True4 True5 False6 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 True2True3 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 = value4 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 = value11 12 def get_value(self):13 return self.__value14 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对象。