思维导图
可迭代对象,迭代器与生成器.pdf

可迭代的对象iterable:

但凡内置有iter方法的对象都称之为可迭代的对象,
因为iter方法这个方法可以把可迭代对象变成迭代器
作者将每个需要取值的对象都加了iter方法

迭代器

指的是迭代取值的工具
迭代是一重复的过程,每一次重复都是基于上一次的结果而来
器是工具
迭代器提供了一种通用的且不依赖于索引的迭代取值方式的功能

  1. 执行可迭代对象下的__iter__方法,返回的值就是一个迭代器
  2. #dic是可迭代对象
  3. dic={'x':2,"y":1,'z':3}
  4. #可迭代对象变成迭代器
  5. iter_dic=dic.__iter__()

迭代器取值

对同一个迭代器取值,next方法,每次取的值都是按序依次不断取值,
而如果是对一个新的迭代器取值, 第一次取的总是第一个值

  1. #取值(这对同一个迭代器的两次取值)
  2. print(iter_dic.__next__())
  3. print(iter_dic.__next__())
  4. #如果取值超过迭代器取值范围,会报错StopIteration,
  5. #也可以当作一种结束信号,表明迭代器取干净了。

可迭代对象与迭代器

1.迭代器一定是个可迭代的对象,但可迭代的对象却不一定是一个迭代器
(可迭代对象可以转变为迭代器)
2.文件对象本身就是一个迭代器

  1. f=open('c.txt','r')
  2. print(f.__next__())

常用的多个值的容器一般都是可迭代对象

注意 :文件属于迭代器(文件本身就是一个迭代器)

  1. #可迭代对象
  2. 只有__iter__方法,没有__next__方法
  3. #迭代器
  4. 1.既内置有__next__方法的对象,执行迭代器__next__方法可以不依赖索引取值
  5. 2.又内置有__iter__方法的对象,执行迭代器__iter__方法得到的仍然是迭代器本身
  1. l=[1,2,4]
  2. iter_1=l.__iter__()
  3. print(iter_1)
  4. print(iter_1 is iter_1.__iter__().__iter__().__iter__())
  5. #调用可迭代对象__iter__得到的是迭代器。
  6. #执行迭代器__iter__方法得到的仍然是迭代器本身
  7. #这这模式可以说是为了for循环做的准备

误区:

迭代是基于老的

  1. l=[1,2,4]
  2. print(l.__iter__().__next__()) #结果:1 生成一个迭代器,并且取了第一个值
  3. print(l.__iter__().__next__()) #结果:1 又生成了一个迭代器,并且取了第一个值

for循环

  1. #调用可迭代对象__iter__得到的是迭代器。
  2. #执行迭代器__iter__方法得到的仍然是迭代器本身
  3. #这这模式可以说是为了for循环做的准备
  4. dic={'x':1,"y":3,'z':2}
  5. iter_dic=dic.__iter__()
  6. #等价于#
  7. iter_dic1=iter(dic)
  8. print(iter_dic)
  9. print(iter_dic1)
  10. #内置方法
  11. print(next(iter_dic))
  12. print(next(iter_dic1)) #底层 print(iter_dic1.__next__())
  13. while True:
  14. try:
  15. print(next(iter_dic1))
  16. except StopIteration:
  17. break
  18. #迭代器的结果只能取一次,因此,即便再加一个while循环,同一个迭代器也无法再次取值

1.可迭代对象变成迭代器
2.能够自己获取迭代器next的值
3.next最后不报错

for循环的本质应该称之为迭代器循环,如果for循环面对的对象仅仅是可迭代对象而不是迭代器,则会生成一个新的迭代器,因此此时for循环可重复使用,但如果面对的对象本身就是一个迭代器,那么for循环也不可重复使用

  1. #1.先调用in后面那个对象的__iter__方法,将其变成一个迭代器
  2. 如果是迭代器__iter__可以变成迭代器
  3. 如果是个可迭代对象__iter__可以变成迭代器
  4. #2.调用next(迭代器),将得到的返回值赋值给变量名
  5. #3.循环往复直到next(迭代器)抛出异常,for会自动捕捉异常StopIteration然后结束循环

迭代器总结:

优点:
1.提供一种通用的且不依赖于索引的迭代取值方式
2.同一时刻在内存中只存在一个值,更节省内存

缺点:
1.取值不如按照索引的方式灵活,(不能取指定的某一个值,而且只能往后取值
2.无法预测迭代器的长度

生成器

大前提:生成器(generator)是一种自定义的迭代器,本质就是迭代器
但凡函数内包含yield关键字,调用函数不会执行函数体代码
会得到一个返回值,该返回值就是生成器对象

  1. def func():
  2. print("=======")
  3. print('+++')
  4. yield 1
  5. print('======')
  6. yield 2
  7. g=func()
  8. l=g.__next__()
  9. L=g.__next__()
  10. print(l)
  11. print(L)
  12. #当触发函数的执行,直到碰到一个yield停下来,并且将yield后的值当作本次next的结果返回

总结:
yield只能在函数内使用
1.yield提供了一种自定义迭代器的解决方案
2.yield可以保存函数的暂停的状态
3.yield对比return
1.相同点:都可以返回值,值的类型与个数都没有限制
2.不同点:yield可以返回多次值(暂停),而return只能返回一次值函数就结束了

  1. '''定义一个生成器,可以生成10位斐波拉契数列,得到斐波那契数列(斐波那契:数列中的每一个值都等于前两个数相加的值[1,1,2,3,5,8,13......)'''
  2. def run(n):
  3. i,a,b=0,1,1
  4. while i<n:
  5. yield a
  6. a, b=b,a+b
  7. i +=1
  8. my_run=run(10)
  9. print(my_run)
  10. print(list(my_run))

了解

对函数不断地进行传值
yield 的表达式形式的应用:x=yield
不停的传值

  1. def run1(name):
  2. print('千与千寻%s准备开吃'%name)
  3. food_list=[]
  4. while True :
  5. food=yield food_list
  6. print("%s吃了%s"%(name,food))
  7. food_list.append(food)
  8. g=run1('无脸男')
  9. print(g)
  10. res1=g.__next__()
  11. print(res1)
  12. #不仅仅把数据送进去赋值给food ,还执行了next方法
  13. res2=g.send('黄金')
  14. print(res2)
  15. res3=g.send('黄金')
  16. print(res3)

send总结(来源网络)

1.当有如 y = yield x 这样的句子时,首先执行等号右半部分,再将结果赋给 y,但显然执行完yield就被冻结了,赋值只能在下一次运行生成器时执行,而下一次初始值为None。
2.send方法可以为生成器传值,send(None) 等价于 Next()
3.第一次运行生成器时如果用send方法,参数只能为None
————————————————
版权声明:本文为CSDN博主「Sheng_1225」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_28915777/article/details/108186963