一、迭代器
什么是迭代?迭代器又会是什么?要想知道这些,那就让攀少带领你走进迭代器的世界。
首先解释一下迭代,即更新换代的意思,这个更新换代是基于上一个版本的。那么我们也就知道迭代器的意思了,器,是工具的意思,迭代器就是迭代取值的工具。
为什么要用迭代器呢?因为他给我们提供了可以不按索引取值的方法。
l = [1,2,3,4] n = 0 while n<len(l): print(l[n]) n += 1
重复+每次迭代都是基于上一次的结果而来的。
需要迭代取值的数据类型:字符串、列表、元组、字典、集合
什么是可迭代对象?只要内置有_iter_方法的都叫可迭代对象
在基本类型中,是可迭代对象的有:str list tuple dict set 文件对象(执行内置的_iter_之后还是本身,没有任何变化)
二、迭代器对象
迭代器对象满足两个条件:1、内置有_iter_方法,2、内置有_next_方法
迭代器一定是可迭代对象,而可迭代对象不一定是迭代器对象
l = [1,2,3,4] iter_l = l._iter_() # 生成一个迭代对象 print(iter_l._next_()) # 迭代器取值,调用_next_ 迭代器取值的话,只能往后依次取,不能后退取值 print(iter_l._next_()) print(iter_l._next_()) print(iter_l._next_()) print(iter_l._next_()) # 如果取完了就会报错
d = {'name':'jason','password':'123','hobby':'piao'} iter_d = d._iter_() # 将可迭代对象d转换成迭代器对象 print(iter_d._next_()) # 迭代器对象的取值,必须用_next_ print(iter_d._next_()) print(iter_d._next_()) print(iter_d._next_()) #如果值取完了,报错StopIteration
出现值取完报错的话,我们一般会进行异常处理,程序如下
while True: try: print(iter_d.__next__()) except StopIteration: print('老母猪生不动了') break
如果出现这样的话就不会发生迭代现象,看下图程序
d = {'name':'jason','password':'123','hobby':'泡m'} iter_d = d.__iter__() print(d.__iter__().__next__()) print(d.__iter__().__next__())
输出为:
为什么会出现这样的情况,原因是我们不停的让可迭代对象转换成迭代器对象,这样的话永远只会让字典中的第一个元素输出。
迭代取值的优缺点:
优点:不依赖于索引取值,内存中永远只占一份空间,不会导致内存溢出
缺点:不能够获取指定的元素,取完之后会报错
三、了解for循环的本质
本质:1.将in后面的对象调用_iter_转换成迭代器对象。2.调用_next_取值。3.内部有异常捕获StopIteration,当_next_报这个错的话就会自动结束程序
四、生成器
前面说了迭代器,那为什么要用生成器呢?显然,用生成器在逼格上要比迭代器高几个等级,它没有那么多冗长代码了,而且性能上一样的高效。生成器是用户自定义的迭代器,本质就是迭代器。
def func(): print('first') yield 666 print('second') yield 777 print('third') yield 888 g = func() print(g) # 生成器初始化:将函数变成迭代器 <generator object func at 0x0000009EB8552CA8> print(g._next_()) print(g._next_())
函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行,yield后面就是调用迭代器_next_方法能得到的值,yield既可以返回一个值也可以返回多个值,并且多个值是以元组的形式返回。
yield帮我们提供了一种自定义生成器方式,将函数运行状态暂停住,可以返回值。与return相同的是,都有返回值,并且可以返回多个,不同的是yield可以返回多次值,return返回一次函数就会立即结束,yield还可以接受外部传入的值。