迭代器与生成器
1.迭代器
1.1什么是迭代?
迭代是一个重复的过程,但是每次重复都是基于上一次重复的结果而继续
1.2什么是迭代器?
迭代器是迭代取值的工具
1.3为什么要用迭代器?(迭代器的优缺点)
优点:1.提供一种不依赖索引取值的方式,使一些没有索引的对象也可以被迭代取值
2.更节省内存,每一次只取一个值。
缺点:1.不如索引取值那样灵活,可能无法立刻就取到需要的值
2.取值一次性,只能往后取,无法预测值的个数
1.4如何用迭代器?
可迭代对象:内置有__iter__方法的对象都称之为可迭代对象
包括: str\ list\ tuple\ dict\ set\ 文件对象
迭代器对象: 内置既有__iter__方法又有__next__方法的对象称为迭代器对象
包括: 文件对象
因此,迭代器对象一定是可迭代对象,但是可迭代对象不一定是迭代器对象!!!
可迭代对象通过调用其内置的__iter__方法,会有一个返回值,这个返回值就是一个对应该可迭代对象的迭代器!
调用返回值中的next方法,可以进行取值!
for循环的底层原理便是用到了迭代器的原理:
1. 调用in后面那个值/对象的__iter__方法,拿到一个迭代器对象iter_obj
2. 调用迭代器对象iter_obj.__next__()将得到的返回值赋值变量名k,循环往复直到取值完毕抛出异常StopIteration
3.捕捉异常结束循环
迭代器练习:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#利用迭代器的原理,取出字典中的值 d={'k1':111,'k2':222,'k3':333} #d是一个可迭代对象 iter_d=d.__iter__() #iter_d是一个迭代器 while True: try: v=iter_d.__next__() print(v) except StopIteration: break ###当我迭代取完值后,我再去值的时候就会因为取不到值而报错,这个时候我们可以用try--###---except机制,捕捉异常,是代码不报错,正常走下去!
2.生成器
2.1定义:生成器就是一种自定义的迭代器
2.2如何得到生成器?
但凡函数内出现yiled关键字,调用函数执行到yiled关键字处时暂停函数执行,会得到一个跟在yiled后面的返回值,该返回值就是生成器对象,即自定义的迭代器。
注意:得到的是一个生产器对象哦,并不是一个普通的值
def func(): print('first') yield 1 print('second') yield 2 print('third') yield 3 g=func() print(g) #输出为<generator object func at 0x0000021B70E557D8> #需要在代码后写上next(g)才能把值输出来
2.3 yield关键字:提供一种自定义迭代器的解决方案
yield & return
相同点:都可以返回值,返回值没有类型限制\个数限制
不同点:return 只能返回一次值,yield却可以让函数暂时在某一个位置停留,下一次再调用
next 的时候从上次暂停的位置继续往下执行,可以返回多次值
小练习:利用生成器做一个自定义的随机数取值函数,限定范围和步长取值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def my_range(start,end,step): while start <end: yield start start+=step res=my_range(1,5,3) while True: try: print(next(res)) except StopIteration: break
3.递归函数
定义:再调用一个函数的过程又直接或者间接地调用该函数本身,称之为递归调用
递归必须满足两个条件:1.每进入下一次递归调用,问题的规模都应该有所减少
2.递归必须有一个明确的结束条件
递归有两个明确的阶段:1.回溯 2.递推
回溯是指一个函数在其内部又调用了它这个函数(参数可以不同),减小其规模,进入到了一个循环的过程。
递推指的是在回溯到一个阶段,最后的函数满足一定的条件时,最后一个函数结束执行,然后往前返回,函数结束执行的过程。
小练习:利用递归函数,将列表中所有数字输出来
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func(list1): for item in list1: if type(item) is not list: print(item) else: func(item) l=[1,[2,[3,[4,[5,[6,[7,[8,[9,]]]]]]]]] func(l)
4.二分法
取对象的中间值,与要寻找的值进行比较,然后进行切片,继续这个过程,直到找到这个值为止(或者直到对象中只有一个值还没有找到需要的值,那么对象中没有需要的值)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def two_fen(num,list1): mid_index=len(list1)//2 if len(list1)==0: print('列表中没有这个值') return if num>list1[mid_index]: return two_fen(num,list1[mid_index+1:]) elif num<list1[mid_index]: return two_fen(num,list1[:mid_index]) else: return num nums=[3,5,7,11,13,23,24,76,103,111,201,202,250,303,341] res=two_fen(24,nums) print(res)
了解知识点:
在上述代码中,如果在使用递归函数时直接使用two_fen(num,list1[mid_index+1:]),这种方法而没有用retuen 时,
这个递归函数最终是没有返回值的。这个知识点在博客Python 递归函数返回值为None的解决办法中有详解。