迭代和递归
一:迭代器协议
1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)
2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)
3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。
二:for循环 for循环的本质:循环所有对象,全都是使用迭代器协议
遍历方式:
#for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法, # 即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器, # 然后使用迭代器协议去实现循环访问__next__,这样所有的对象就都可以通过for循环来遍历了 #对列表的遍历(字符串,元祖) l=[1,2,3] for i in l: #i_l=l.__iter_() i_l.__next__() print(i) iter_l=l.__iter__() #遵循迭代器协议,生成可迭代对象(for循环机制) print(iter_l.__next__()) print(iter_l.__next__()) index=0 while index < len(l): print(l[index]) index+=1 s={1,2,3} #集合本是无序的,采用while循环无法遍历,但是for循环可以 for i in s: print(i) iter_s=s.__iter__() #遵循迭代器协议,生成可迭代对象(for循环机制) print(iter_s) print(iter_s.__next__()) print(iter_s.__next__()) dic={'a':1,'b':2} iter_d=dic.__iter__() print(iter_d.__next__()) f=open('a.txt','r+') iter_f=f.__iter__() print(iter_f.__next__(),end='') print(iter_f.__next__(),end='')
三:补充内置函数next
l=['die','erzi','sunzi','chongsunzi'] #吧所有内容放内存中 iter_l=l.__iter__()#可迭代对象,节省内存 print(iter_l.__next__()) print(iter_l.__next__()) print(next(iter_l))#第二种方式 print(next(iter_l))
四:三元表达式
#三元表达式 name='alex' res='sb' if name=='alex' else '帅哥' print(res)
五:生成器
可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象
Python有两种不同的方式提供生成器:
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
为何使用生成器之生成器的优点
Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果。这也是生成器的主要好处。
5.1 生成器表达式和列表解析
1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式基于next方式运行更节省内存
3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
1 sum(x ** 2 for x in xrange(4))
而不用多此一举的先构造一个列表:
1 sum([x ** 2 for x in xrange(4)])
#列表解析 egg_list=[] for i in egg_list: egg_list.append('鸡蛋%s'%i) print(egg_list) l=['鸡蛋%s'%i for i in range(10) ] #内存列表 print(l) l1=['鸡蛋%s'%i for i in range(10) if i > 5] print(l1) l1=['鸡蛋%s'%i for i in range(10) if i > 5 else i]#没有四元表达式 laomuji=('鸡蛋%s'%i for i in range(10)) #生成器表达式 print(laomuji) print(laomuji.__next__()) print(laomuji.__next__()) print(laomuji.__next__()) print(laomuji.__next__()) #生成器表达式 print(sum(i for i in range(100000000)))#几乎不占内存 #生成器表达式好处直接生成__next__函数。 g_l=(i for i in range(10)) print(g_l) g1=g_l.__next__() print(g1) g2=g_l.__next__() print(g2)
5.2 生成器函数
#生成器函数 def test(): yield 1 yield 2 yield 3 yield 4 res=test() print(res) print(res.__next__()) print(res.__next__()) print(res.__next__()) print(res.__next__()) print(res.__next__()) def product_baozi(): for i in range(100): print('正在生成包子') yield '包子%s' %i print('开始卖包子') pro_b=product_baozi() baozi1=pro_b.__next__() baozi1=pro_b.__next__() baozi1=pro_b.__next__()
yield 优点
def xiadan(): ret=[] for i in range(100): ret.append('鸡蛋%s' %i) return ret print(xiadan()) #缺点一:占空间大 #缺点二:效率低 def xiadan(): for i in range(100): yield '鸡蛋%s' %i alex_lmj=xiadan() jidan=alex_lmj.__next__() jidan=alex_lmj.__next__() print('fgh取鸡蛋',jidan)
注意事项:生成器只能遍历一次(母鸡一生只能下一定数量的蛋,下完了就死掉了)
#人口 def get_population(): with open('renkoupucha', 'r', encoding='utf-8') as f: for i in f: yield i g=get_population() print(g.__next__()) s1=eval(g.__next__()) print(type(s1)) print(s1['population']) all_pop=sum(eval(i)['population'] for i in g) print(all_pop) for p in g: print(eval(p)['population']/all_pop)#g已经遍历完了,不会再执行该操作 #在我们执行sum语句的时候,就遍历了我们的生成器, # 当我们再次遍历我们的生成器的时候,将不会有任何记录。所以,上面的代码不会有任何输出。 #生成器只能遍历一次
6.生产者消费模型
#生产者消费模型 import time def producter(): ret=[] for i in range(100): time.sleep(0.1) ret.append('包子%s' %i) return ret def consumer(res): for index,baozi in enumerate(res): time.sleep(0.1) print('第%s个人,吃了%s' %(index,baozi)) res=producter() consumer(res) #yield相当于return控制的是函数的返回值 #x=yield的另外一个特性,接受send传过来的值,赋给x def test(): print('开始啦') first=yield #因为没有返回值,所以返回none print('第一次',first) yield 2 print('第二次') t=test() res=t.__next__() #next(t) print(res) # t.send(None) res=t.send('函数停留在first那个位置,我就是给first赋值的') print(res) #生产者消费模型继续(单线程里的并发操作) # import time def consumer(name): print('我是[%s],我准备开始吃包子了'%name) while True: baozi=yield time.sleep(1) print('%s 很开心的吧[%s]吃掉了' %(name,baozi)) def producer(): c1 = consumer('wupeiqi') c2 = consumer('wupeiqi1') c1.__next__() c2.__next__() for i in range(10): time.sleep(1) c1.send('包子 %s' %i) c2.send('包子 %s' % i) producer()