1.什么是迭代器
迭代器:迭代取值的工具
迭代:更新换代(重复)的过程,每次的迭代都必须基于上一次的结果
2.为什么要用
迭代器给你提供了一种不依赖于索引取值的方式
3.可迭代对象
只要内置有__iter__方法的都叫做可迭代对象
补充:针对双下线开头双下划线结尾的方法
推荐读:双下+方法名
基本数据类型中除了数字型都是可迭代对象,文件迭代后还是自己,可迭代对象执行内置的__iter__方法得到就是该对象的迭代器对象 # res = d.__iter__() # res = iter(d) # print(s.__len__()) # 简化成了len(s)
4.迭代器总结
1.可迭代对象:内置有__iter__方法的
2.迭代器对象:既内置有__iter__也内置有__next__方法
3.迭代取值:
优点:
1.不依赖于索引取值
2.内存中永远只占一份空间,不会导致内存溢出
缺点:
1.不能够获取指定的元素
2.取完之后会报StopIteration错
迭代器对象 1.内置有__iter__方法 2.内置有__next__方法 ps:迭代器一定是可迭代对象,而可迭代对象不一定是迭代器对象 3.迭代器对象无论执行多少次__iter__方法得到的还是迭代器对象本身 4.迭代器取值只能往后依次取 不能后退
d = {‘name‘:‘jason‘,‘password‘:‘123‘,‘hobby‘:‘泡m‘}
iter_d = d.__iter__() #生成一个迭代器,将可迭代对象d转换成迭代器对象
print(iter_d.__next__()) # name迭代器对象的取值 必须用__next__
print(iter_d.__next__()) #password
print(iter_d.__next__()) #hobby
print(iter_d.__next__()) # 取完了 报错StopIteration ,都报错了你能忍?怎么办?
while True:
try:
print(iter_d.__next__())
except StopIteration: #上面的print报错后如果和条件中的报错信息一样不会报错,而是继续向下执行,不一样的错误还是会报错
# print(‘这谁顶得住!‘)
break
for循环内部的本质 :(for循环后面的in关键 跟的是一个可迭代对象)
1.将in后面的对象调用__iter__转换成迭代器对象(不管谁来,先执行_iter_这个操作,因此文件即使是迭代器对象也要拥有_iter_方法才能支持for循环)
2.调用__next__迭代取值
3.内部有异常捕获,捕获StopIteration,当__next__报这个错 自动结束循环
生成器:用户自定义的迭代器,本质就是迭代器 def func(): print(‘first‘) yield 相应参数 # 函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行 g = func() # 生成器初始化:将函数变成迭代器,函数体代码不会执行
# yield后面跟的值就是调用迭代器__next__方法你能得到的值
# yield既可以返回一个值也可以返回多个值 并且多个值也是按照元组的形式返回
def func():
print(‘first‘)
yield 666 # yield相当于一个暂停器,并且有返回功能
print(‘second‘)
yield 777
print(‘forth‘)
yield
g = func() # 生成器初始化:将函数变成迭代器
print(g) #<generator object func at 0x0000000002170F68> 是一个迭代器
print(g.__next__()) #666 调用一次_next_出来一个返回值,然后程序会停在yield,等待下一个启动器触发
print(g.__next__()) #777
print(g.__next__()) #None print(‘forth‘)后面如果不写 yield,就会报错,写了后面没有值相当于空返回None结束程序
1.内置的range for i in range(1,10,2): print(i) #13579 2.自定义一个range def my_range(start,end,step=1): while start < end: yield start start += step for j in my_range(1,100,2): print(j) #13579
# yield支持外界为其传参 def dog(name): print(‘%s 准备开吃‘%name) while True: food = yield print(‘%s 吃了 %s‘%(name,food)) g = dog(‘egon‘) #无结果 当函数内有yield关键字的时候,调用该函数不会执行函数体代码,而是将函数变成生成器 g.__next__() #egon 准备开吃 这一次运行一定不能少,必须有这行代码生成器才真正执行,遇到yield暂停,必须先将代码运行至yield ,才能够为其传值 g.__next__() #egon 吃了 None 遇到一次_next_ yield就会放行一次,没传参数就返回None,经循环再次停在yield g.send(‘狗不理包子‘) #egon 吃了 狗不理包子 给yield左边的变量传参 , 触发了__next__方法,执行一次然后再次循环到yield停止 g.send(‘饺子‘) #egon 吃了 饺子 再一次触发_next_方法再输出一次
1.yield 1.帮你提供了一种自定义生成器方式 2.会帮你将函数的运行状态暂停住 3.可以返回值 2.与return之间异同点 相同点:都可以返回值,并且都可以返回多个 不同点: yield可以返回多次值,而return只能返回一次函数立即结束 yield还可以接受外部传入的值
1.当遇到特别大的可迭代对象,节省内存 res = (i for i in range(1,100000000) if i != 4) # 生成器表达式,好像好像元祖生成式,可惜并不是 print(res) print(res.__next__()) #1 print(res.__next__()) #2 # 生成器不会主动执行任何一行代码,必须通过__next__触发代码的运行,要一个给一个 2.读取文件内字符长度: 1.一次读出直接统计,占内存 f = open(‘xxx.txt‘,‘r‘,encoding=‘utf-8‘) data = f.read() print(len(data))
f.close() 2.一行一行读,还可以 with open(‘xxx.txt‘,‘r‘,encoding=‘utf-8‘) as f: n = 0 for line in f: n += len(line) print(n) 3.迭代器读,真牛逼 with open(‘xxx.txt‘,‘r‘,encoding=‘utf-8‘) as f: g = (len(line) for line in f) print(sum(g))
启动生成器进行迭代有以下几种方法:
第一种:for循环,for循环的本质就是调用了iter和next方法进行了迭代
第二种:调用next方法
第三种:调用send方法
第四种:数据类型强制转换,比如使用list()强制转换。
只要没有以上四种方法进行迭代,那么生成器就没有进行运算
4.6 面试题
原文:https://www.cnblogs.com/xp1315458571/p/11192085.html