1. 迭代
第一,迭代需要重复进行某一操作
第二,本次迭代的要依赖上一次的结果继续往下做,如果中途有任何停顿,都不能算是迭代.
2. 可迭代对象
除了整型之外,python内的基本数据类型都是可迭代对象,包括文件对象。
一个对象是否可迭代,关键看這个对象是否有__iter__()方法。
3. 迭代器
容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取。简单来说,就好比一个盒子,我们可以往里面存放数据,也可以从里面一个一个地取出数据。
在python中,属于容器类型地有:list,dict,set,str,tuple.....。容器仅仅只是用来存放数据的,我们平常看到的 l = [1,2,3,4]等等,好像我们可以直接从列表这个容器中取出元素,但事实上容器并不提供这种能力,而是可迭代对象赋予了容器这种能力。
迭代器与可迭代对象仅仅就是__next__()方法的有无。
4. for内部机制剖析
L = [1,2,3,4,5]是一个可迭代对象。而且可迭代对象是不可以直接从其中取到元素。那么为啥我们还能从列表L中取到元素呢?这一切都是因为for循环内部实现。在for循环内部,首先L会调用__iter__()方法,将列表L变为一个迭代器,然后这个迭代器再调用其__next__()方法,返回取到的第一个值,这个元素就被赋值给了i,接着就打印输出了。
l = [1,2,3,4,5,6]
item = l.__iter__() # 将l变为迭代器
print(item.__next__()) # 迭代器调用next方法,并且返回取出的元素
print(item.__next__())
print(item.__next__())
print(item.__next__())
print(item.__next__())
print(item.__next__())
print(item.__next__()) # 报错
#######输出结果#############
1 2 3 4 5 6
######上面为什么报错呢??##########
#当调用了最后一个next方法,没有下一个元素可取
#就会报错StopIteration异常错误。你可能会想会
#为什么for循环没有报错?答案很简单,因为for循
#环内部帮我们捕捉到了这个异常,一旦捕捉到异常
#说明,迭代应该结束了!
###########################
当我们试图用for循环来迭代一个可迭代对象时候,for循环在内部进行了两步操作:第一,将可迭代对象S变为迭代器M;第二,迭代器M调用__next__()方法,并且返回其取出的元素给变量i。
你可能看见过这种写法,for i in iter(M):xxx ,其实这一步操作和我们上面没什么区别。iter()函数,就是将一个可迭代对象M变为迭代器也就是M调用__iter__()方法,然后内部在调用__next__()方法。也就是说,
M = [1,2,3,4,5]
for i in iter(M): # 等价于 M.__iter()__ 人为显示调用
print(i)
for i in M: # 解释器隐式调用
print(i)
#################
#
#上面输出的结果完全一样
#
#################
还有next(M)等价于M.__next__。
迭代器优点:
1.节约内存
2.不依赖索引取值
3.实现惰性计算(什么时候需要,在取值出来计算)
5.生成器(本质就是迭代器)
生成器就是迭代器。
Python有两种不同的方式提供生成器:
1.生成器函数(函数内部有yield关键字):常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
生成器小结:
1.是可迭代对象
2.实现了延迟计算,省内存啊
3.生成器本质和其他的数据类型一样,都是实现了迭代器协议,只不过生成器附加了一个延迟计算省内存的好处,其余的可迭代对象可没有这点好处!