博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python-迭代器和生成器
阅读量:4560 次
发布时间:2019-06-08

本文共 6832 字,大约阅读时间需要 22 分钟。

一、递归和迭代:

  1、递归(问路的案例)

    递归算法是自己调用自己的过程

  2、迭代(父生子,子生孙)   

    更新换代

二、迭代器协议:

  1、迭代器协议:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就触发StopTteration异常,已终止迭代(只能往下走,不能往上走)

  2、可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)

  3、协议是一种约定,可迭代对象实现了迭代器协议,Python的内部工具(for循环,sum,max,min函数等)使用迭代器协议访问对象

  4、for循环的本质就是遵循迭代器协议取访问对象,那么for循环的对象肯定都是迭代器。

  5、不可迭代对象:字符串,列表,元组,字典,集合,文件对象。只不过for循环时,调用了他们的内部__iter__()方法,把他们变成了可迭代对象

    -注-

      1、生成器是可迭代对象

      2、实现了延迟计算,看内存(按需执行)  

      3、生成器本质和其他类型一样,都是实现了迭代器协议,只不过生成器是一边计算一边生成,从而节省内存空间,其余的可迭代对象没有这个功能

三、迭代器:  

  1、遵循迭代器协议的访问方式:

1 x='hello' # 非可迭代对象 2 # print(dir(x)) 3 iter_test=x.__iter__() #调用字符串的了iter方法 4  5 print(iter_test)  6 print(iter_test.__next__())  #获取第1个值 ,调用可迭代对象的next方法 7 print(iter_test.__next__())  #获取第2个值 8 print(iter_test.__next__())  #获取第3个值 9 print(iter_test.__next__())  #获取第4个值10 print(iter_test.__next__())  #获取第5个值11 print(iter_test.__next__())  #超出边界,当for循环结束时,捕捉到StopIteration异常,他就会终止迭代

 

  2、for循环的访问方式:

    for循环 l 本质是遵循迭代器协议的访问方式,先调用l 的__iter__()方法,使其成为一个可迭代对象,在调用next方法直到for循环捕捉到StopIteration异常

1 # l=[1,2,3]2 # for i in l:  #i_l=l.__iter_()  i_l.__next__()3 #     print(i)

 

  3、用索引方式遍历列表的值

1 l=[1,2,3,4]2 3 index=04 while index < len(l):5     print(l[index])6     index += 1

 

  4、用迭代器的方式遍历列表

1 l=[1,2,3]2 iter_l=l.__iter__()       #遵循迭代器协议,生成可迭代对象3 print(iter_l.__next__())  #取列表的值4 print(iter_l.__next__())  #取列表的值5 print(iter_l.__next__())  #取列表的值

 

  5、迭代的方式遍历集合

s={1,2,3}iter_s=s.__iter__()    #通过iter方法print(iter_s)print(iter_s.__next__())   #调用nextprint(iter_s.__next__())print(iter_s.__next__())print(iter_s.__next__())  #超出边界,当for循环结束时,捕捉到StopIteration异常,终止迭代

 

  6、迭代的方式遍历字典(默认是key)

dic={
'a':1,'b':2}iter_d=dic.__iter__()print(iter_d.__next__())print(iter_d.__next__())print(iter_d.__next__())

 

  7、迭代的方式访问文件

1 #文件的方式(创建文件test,txt) 2 f=open('test.txt','r+') 3 for i in f: 4  5 =====》》》 6  7  8 f=open('test.txt','r+') 9 iter_f=f.__iter__()   #遵循可迭代原则,转换成迭代器,要的时候拿到内存,可以节约内存空间10 print(iter_f)11 print(iter_f.__next__(),end='')  #第一行12 print(iter_f.__next__(),end='')  #第二行13 print(iter_f.__next__(),end='')  #第三行14 print(iter_f.__next__(),end='')  #执行完了的时候,就捕捉到StopIteration异常,终止迭代

 

  8、while实现for循环

1 l=[1,2,3,4,5]2 diedai_l=l.__iter__()3 while True:4     try:5         print(diedai_l.__next__())6     except StopIteration:   7         # print('迭代完毕了,循环终止了')8         break   #直接break,捕捉到导常,就不会报StopIteration异常

 

  迭代器总结:

1 l=['die','erzi','sunzi','chongsunzi']   #把所有结果都放在内存中,比较占用内存(所以才会引出生成器)2 3 iter_l=l.__iter__()        #转成迭代器形式,可以在任意位置传输(也叫可迭代对象)4 print(iter_l)5 print(iter_l.__next__())    #第一次调用,得到的结果:die6 print(iter_l.__next__())    #第二次调用, 得到的结果:erzi7 print(iter_l.__next__())    #第三次调用, 得到的结果:sunzi8 print(iter_l.__next__())    #第四次调用, 得到的结果:chongsunzi9 print(iter_l.__next__())    #超出边界,捕捉到StopIteration异常,终止迭代

 

  —注—:    

    next是python的内置函数

    说明:使用next内置函数的next()方法,就是在调用l.__iter__(),下的 __next__()方法 

1 l=['die','erzi','sunzi','chongsunzi']2 iter_l = l.__iter__()3 print(next(iter_l))        #next()---->iter_l.__next__()4 print(next(iter_l))5 print(next(iter_l))6 print(next(iter_l))

 

四、生成器

  1、生成器:

    生成器就是迭代器,可以理解为一种数据类型,这种数据类型实现了迭代器协议,其他的数据类型需要调用自己内置的__iter_方法,所以生成器就是可迭代对象。

  2、生成器分类以及在Python中的表现形式:(Python有两种不同的方式提供生成器)

    ①生成器函数:常规函数定义,但是,使用yield 语句代替return语句,但是,yield在同一层函数中,可以多次使用,一次返回一个结果,返回一个结果后,将函数设置为挂起状态,以便下次从他离开的地方继续执行。

    ②生成器表达式:类似于列表的推导,但是生成器返回按需产生结果的一个对象,而不是一次性构建一个结果列表。

  3、生成器示例之 yield

1 def test():2     yield 1    #只要有yield就是生成器3     yield 2    #他可以yield多次,yield可以保存函数状态4     yield 35 g=test()6 print('来自函数',g)7 print(g.__next__())   #生成器自动实现了迭成器,所以会有__next__()方法。8 print(g.__next__())   #运行一次,相当于保存的是上一次内存里状态的结果9 print(g.__next__())

 

  4、补充 知识 之 三元表达式:

1 #三元表达式演变过程2 3 # name='alex'4 # 'SB' if name == 'alex' else '帅哥'  #if判断name=alex就,返回SB;如果不等于alex,就返回帅哥。但SB要写在最前面。

 

  5、生成器之表达式和列表解析  

    5.1、for循环生成一个列表

1 1 egg_list=[]2 2 for i in range(10):3 3     egg_list.append('鸡蛋%s' %i)4 4 print(egg_list)5 6 ----->7 8 1 ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']

 

    5.2、列表解析生成一个列表

1 l=['鸡蛋%s' %i for i in range(10)] # 也可以是两元2 print(l) 3 ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']

 

    5.3 三元表达式生成列表

#鸡蛋>5l1=['鸡蛋%s' %i for i in range(10) if i > 5 ]# l1=['鸡蛋%s' %i for i in range(10) if i > 5 else i] #没有四元表达式print(l1)#鸡蛋<5l2=['鸡蛋%s' %i for i in range(10) if i < 5]print(l2)------------->1 #鸡蛋>5结果:2 ['鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']3 4 #鸡蛋<5结果:5 ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']

 

    5.4、生成器表达式基于迭代器next方法取值

1 laomuji=('鸡蛋%s' %i for i in range(10)) #生成器表达式 2 print(laomuji) 3  4 print(laomuji.__next__())  #基于迭代器__next__方法进行取值 5 print(laomuji.__next__()) 6 print(next(laomuji)) 7 print(next(laomuji)) 8 print(next(laomuji)) 9 print(next(laomuji))10 print(next(laomuji))11 print(next(laomuji))12 print(next(laomuji))13 print(next(laomuji))14 #print(next(laomuji))   #超出边界,当for循环结束时,捕捉到StopIteration异常,终止迭代

 

     5.5、其他

1 l=[1,2,3,34]2 #map(func,l)   #可迭代对象3 print(sum(l))  #求和,使用的是__iter__()方法转换成可迭代对象4 5 #生成1000000006 print(sum(list(range(100000000)))) # 会很卡,一次性生成一个列表7 8 #sum传给生成器生成一个列表9 print(sum(i for i in range(10000000000000)))   #没有运行结果

 

  6、生成器示例之 生孩子:

1 import time 2 def test(): 3     print('开始生孩子啦.......') 4     print('开始生孩子啦.......') 5     print('开始生孩子啦.......') 6     yield '我'  #return  7     time.sleep(3) 8     print('开始生儿子啦.......') 9     yield '儿子'10 11     time.sleep(3)12     print('开始生孙子啦.......')13     yield '孙子'14 15 res=test()16 print(res)17 print(res.__next__())   # 打印我 就挂起,后面的不在执行18 print(res.__next__())19 print(res.__next__())

 

  7.send触发yield返回值原理

1 #yield 3相当于return 控制的是函数的返回值 2 #x=yield的另外一个特性,接受send传过来的值,赋值给x 3  4 def test(): 5     print('开始啦') 6     firt = yield 1      # return 1,first=None 7     print('第一次', firt) 8     yield 2 9     print('第二次')10 11 t = test()12 res = t.__next__()  # next(t)13 print(res)14 # t.__next__()15 res=t.send(None)16 # res = t.send  # ('函数停留在first那个位置,我就是给first赋值的')17 print(res)

 

  8.吃包子

1 import time 2 def producer(): 3     ret=[] 4     for i in range(100): 5         time.sleep(0.1) 6         ret.append('包子%s' %i) 7     return ret 8  9 def consumer(res):10     for index,baozi in enumerate(res):11         time.sleep(0.1)12         print('第%s个人,吃了%s' %(index,baozi))13 14 res=producer()15 consumer(res)16 17 18 19 ------>20 21 22 23 24 第0个人,吃了包子025 第1个人,吃了包子126 第2个人,吃了包子227 第3个人,吃了包子328 第4个人,吃了包子429 第5个人,吃了包子530 ....

 

    总结:

    1.把列表解析的[]换成()得到的就是生成器表达式

    2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

    3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和。

 

 补充:send使用 类似next

def foo():    print('---')    yield 1    print('****')    count = yield 2    print(count)a = foo()s1 = a.send(None) # == a.next() ,第一次send时,如果之前没有执行过next,先传入Noneprint(s1)s2 = a.send('aaa') # 先yield 后赋值print(s2)

 

 

  

转载于:https://www.cnblogs.com/JerryZao/p/8634205.html

你可能感兴趣的文章
SoupUI接口测试学习分享
查看>>
HDU2275
查看>>
tomcat:A docBase * inside the host appBase has been specifi, and will be ignored
查看>>
动态创建按钮及处理OnClick事件
查看>>
字符集
查看>>
《Linux命令行与shell脚本编程大全 第3版》Linux命令行---51
查看>>
《Linux命令行与shell脚本编程大全 第3版》高级Shell脚本编程---27
查看>>
jQuery最佳实践
查看>>
DelphiXE2 DataSnap开发技巧收集
查看>>
HoloLens开发手记 - Unity之Keyboard input 键盘输入
查看>>
关于日历
查看>>
荣品KING3288开发板升级啦!
查看>>
系统产生死锁的四个必要条件
查看>>
初心易得,始终难守
查看>>
北京集训DAY4
查看>>
编译 ACE
查看>>
JDBC(1)
查看>>
《程序是怎样跑起来的》第五章
查看>>
配置SSH单向无密码访问
查看>>
深入浅出Docker(五):基于Fig搭建开发环境
查看>>