~玉米糊~
慢慢来,也会很快。 非宁静无以志学,学什么都一样,慢慢打基础,找规律、认真、坚持,其余的交给时间。

1、迭代器介绍

迭代器即用来迭代取值的工具,而迭代是重复反馈过程的活动。其目的通常是为了逼近所需的目标或结果,每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值,单纯的重复并不是迭代

goods=['mac','lenovo','acer','dell','sony']

index=0
while index < len(goods):
    print(goods[index])
    index+=1

 

上述while循环才是一个迭代过程,不仅满足重复,而且以每次重新赋值后的index值作为下一次循环中新的索引进行取值,反复迭代,最终可以取尽列表中的值

注意:

  • 上面这个迭代方法只适合序列类型,并不适合字典、集合、文件对象的迭代取值。
  • 有人会说for循环可以对字典、文件对象、集合进行循环取值,其实for循环用到的是迭代器,因此这里没有用for循环为例说明,后面会具体说迭代器和可迭代对象的区别与联系

(1)可迭代对象

通过索引的方式进行迭代取值,实现简单,但仅适用于序列类型:字符串,列表,元组。对于没有索引的字典、集合、文件对象等非序列类型,必须找到一种不依赖索引来进行迭代取值的方式,这就用到了迭代器

可迭代对象(Iterable)。从语法形式上讲,内置有__iter__方法的对象都是可迭代对象,字符串、列表、元组、字典、集合、打开的文件都是可迭代对象。

{'name':'amy'}.__iter__
{7,8,9}.__iter__
……

 

重点:

像我们range返回的就是一个优化了的可迭代对象,为什么叫优化了的?
因为普通的可迭代对象就像python2中的range, 返回的是个列表, [1,2,3,4], 可以通过索引取值

 

(2)迭代器对象

调用obj.iter()方法返回的结果就是一个迭代器对象(Iterator)。
除文件对象外,字典、集合、列表等都只是可迭代对象而已,它们可以通过调用iter方法生成迭代器对象,并进行迭代取值。但文件对象在python中使用时,直接生成的就是迭代器对象,当然它也是可迭代对象。文件对象可以直接调用next函数,只有迭代器对象才能调用next方法,因此文件对象是迭代器对象。执行迭代器对象.iter()方法得到的仍然是迭代器本身,而执行迭代器对象.next()方法就会计算出迭代器中的下一个值。

>>> s={1,2,3} # 可迭代对象s
>>> i=iter(s)  # 本质就是在调用s.__iter__(),返回s的迭代器对象i,
>>> next(i) # 本质就是在调用i.__next__()
1
>>> next(i)
2
>>> next(i)
3
>>> next(i)  #抛出StopIteration的异常,代表无值可取,迭代结束,要想继续取值,除非再重新生成一个迭代器。

 

为什么文件对象要直接设置成迭代器对象,集合、字典等不设置成迭代器对象呢?

 

答:首先我们应该明白迭代器这种需要一个值,next方法取一个值,这样是降低了内存的消耗的。
集合、字典等定义下来,本来就不是用来存很多、很多东西的。但是一个文件对象却可以很大很大,因此必须直接生成迭代器对象,控制内存的消耗。

 

2、for循环原理

有了迭代器后,我们便可以不依赖索引迭代取值了,使用while循环的实现方式如下

dic = {'a':1,'b':2,'c':3}
d_iterator = iter(dic) #d_iterator便是一个迭代器对象,iter方法生成的就是一个迭代器对象
while True: # while循环的循环体是进行循环迭代取值的
    try:
        print(next(d_iterator))
    except(StopIteration): # 捕获异常
        break # 异常处理

 

for循环又称为迭代循环,in后可以跟任意可迭代对象,上述while循环可以简写为:

dic = {'a':1,'b':2,'c':3}
for i in dic:
    print(i)

 

for 循环在工作时,首先会调用可迭代对象dic内置的iter方法拿到一个迭代器对象,然后再调用该迭代器对象的next方法将取到的值赋给i,执行循环体完成一次循环,周而复始,直到捕捉StopIteration异常,结束迭代

为什么文件对象中也需要有iter方法呢?
它不是已经是迭代器对象了吗,而且前面说迭代器调用iter方法屁用没有,得到的还是本身。

答:这是一个专门为统一for循环而设计的,因为for循环中你不确定自己in后面到底是不是迭代器对象,难道还要判断一下吗?
那不是太麻烦了,无论谁来,只要可迭代,我就给你iter方法一下,即使是文件对象,也不影响啥。所以文件对象也需要一个iter方法,拿去让for循环调用。

 

3、迭代器的优缺点

基于索引的迭代取值,所有迭代的状态(迭代的位置信息)都保存在了索引,而基于迭代器实现迭代的方式不再需要索引,所有迭代的状态就保存在迭代器中,然而这种处理方式优点与缺点并存:

(1)优点

为序列和非序列类型提供了一种统一的迭代取值方式
惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用next来计算出一个值,就迭代器本身来说,同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,如列表,需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的。

(2)缺点

除非取尽,否则无法直接获取迭代器的长度
只能取下一个值,不能回到开始,更像是'一次性的',迭代器产生后的唯一目标就是重复执行next方法直到值取尽,否则就会停留在某个位置,等待下一次调用next;若是要再次迭代同个对象,你只能重新调用iter方法去创建一个新的迭代器对象,如果有两个或者多个循环使用同一个迭代器,必然只会有一个循环能取到值。

4、小结

字符串、列表、元组、字典、集合、打开的文件都是可迭代对象。其中字符串、列表、元组是序列类型,可以基于索引迭代取值。

迭代器对象 = iter(可迭代对象)

next(迭代器对象)


————————————————
版权声明:本文为CSDN博主「凤求凰的博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44571270/article/details/106005998

posted on 2022-04-03 22:21  yuminhu  阅读(3)  评论(0编辑  收藏  举报