偏理解
知道for循环后面跟什么 *****
生成器的作业
- 什么是迭代器
迭代就是更新换代
迭代器指的是迭代取值的工具- 为何要用迭代器
器是工具
迭代器提供了一种通用的且不依赖于索引的迭代取值方式的功能
### 迭代器的使用 #单纯的重复不是迭代 # i = 0 # while True: # print(i) # 迭代:重复+每次重复都是基于上一次的结果而进行(不是是单纯的重复) # l = ['a','b','c'] # i = 0 # while i < len(l): # print(l[i]) # i += 1 # # 哪些数据类型需要这样迭代取值 # # 字符串 列表 元组 字典 集合 文件等等 # l = ['a','b','c'] # a = 'abc' # t = ('a','b','c') # dic = {'name':'dahai','age':18} # i = 0 # while i < len(l): # print(l[i]) # i += 1 # 所以我们需要一种不依赖索引取值的方式 # 迭代器提供了一种通用的且不依赖于索引的迭代取值方式的功能
# 可迭代对象 #一 :可迭代的对象iterable:但凡内置有__iter__方法的对象都称之为可迭代的对象 # 作者是个天才,每个需要取值的都加了__iter__方法 #可迭代的对象:str,list,tuple,dict,set,文件对象 a = 1 # a.__iter__没有 b = 1.1 # b.__iter__没有 c = 'hello' print(c.__iter__()) d = ['a', 'c'] print(d.__iter__()) e = {'x': 1} print(e.__iter__()) g = {1, 2, 3} # g是可迭代对象 # g.__iter__()会生成迭代器 print(g.__iter__()) f = open('b.txt', 'w') print(f.__iter__())
# 迭代器 # 执行可迭代对象下的__iter__方法,返回的值就是一个迭代器对象 dic = {'x': 1, 'y': 2, 'z': 3} # 迭代器对象变成迭代器 iter_dic = dic.__iter__() # iter_dic迭代器 print(iter_dic.__next__()) print(iter_dic.__next__()) print(iter_dic.__next__()) # 列表不依赖索引取值 l = [1, 2, 3] iter_l = l.__iter__() print(iter_l.__next__()) print(iter_l.__next__()) print(iter_l.__next__()) # #StopIteration应该被当成一种结束信号,代表迭代器取干净了 print(iter_l.__next__())
# 误区 l = [1, 2, 3] print(l.__iter__().__next__()) # 基于新的迭代器对象 print(l.__iter__().__next__()) # 迭代是基于老的 iter_l = l.__iter__() print(iter_l.__next__()) print(iter_l.__next__())
可迭代对象与迭代器 *****
可迭代对象
只有__iter__方法,没有__next__方法
除了文件其他容器都是可迭代对象
迭代器
- 既内置有__next__方法的对象,执行迭代器__next__方法可以不依赖索引取值
- 又内置有__iter__方法的对象,执行迭代器__iter__方法得到的仍然是迭代器本身
迭代器一定是可迭代的对象,而可迭代的对象却不一定是迭代器对象
可迭代的对象只需要有__iter__()
迭代器对象 iter() next()
f = open('b.txt', 'w') print(f.__iter__()) l = [1, 2, 3] iter_l = l.__iter__() # 调用可迭代的对象__iter__得到的是迭代器, # 执行迭代器__iter__方法得到的仍然是迭代器本身,那么有什么用 # 为了for循环 print(iter_l is iter_l.__iter__().__iter__().__iter__())
# iter() next() dic = {'x': 1, 'y': 2, 'z': 3} # iter_dic = iter(dic) print(iter_dic) # 底层 print(dic.__iter__()) print(next(iter_dic)) # 底层 print(iter_dic.__next__())
# 解决迭代器报错 # 异常捕获 dic = {'x': 1, 'y': 2, 'z': 3} # iter_dic = iter(dic) # 异常捕获 while True: try: print(next(iter_dic)) except StopIteration: break print('=========') # # 同一个迭代器只能完整地取完一次值 while True: try: print(next(iter_dic)) except StopIteration: break
# 有没有一种好的方法自己把 # 1.可迭代对象变成迭代器对象 # 2.能够自己获取迭代器对象next的值 # 3.next最后不报错 #for本质应该称之为迭代器循环 ***** # 那么以后大家知道for循环后面可以跟迭代器和可迭代对象 #底层工作原理 #1. 先调用in后面那个对象的__iter__方法,将其变成一个迭代器 # 如果是个迭代器__iter__可以变成迭代器 # 如果是个可迭代对象__iter__可以变成迭代器 #2. 调用next(迭代器),将得到的返回值赋值给变量名 k #3. 循环往复直到next(迭代器)抛出异常,for会自动捕捉异常StopIteration然后结束循环 # 可迭代对象包含迭代器对象 # 文件对象是迭代器,那么for循环也会自动调用__iter__,那么还是一个迭代器 # 那么for循环的机制就可以通用,这就是为什么迭代器对象里面也有一个__iter__的方法的原因 dic = {'x': 1, 'y': 2, 'z': 3} for k in dic: print(k) # 为什么下一次又可以 # 因为又做了上面三件事 又变成了一个新的dic迭代器 for k in dic: print(k)
#迭代器总结 # 优点: # 1. 提供一种通用的且不依赖于索引的迭代取值方式 # 2. 同一时刻在内存中只存在一个值,更节省内存 # 缺点: # 1. 取值不如按照索引的方式灵活,(不能取指定的某一个值,而且只能往后取) # 2. 无法预测迭代器的长度
obj_iter = range(1, 10) # obj_iter可迭代对象 print(obj_iter) obj_next = iter(obj_iter) print(obj_next.__next__()) print(obj_next.__next__()) print(obj_next.__next__()) print('迭代器的for循环') # 1 开 1 4 for i in obj_next: print(i) print('可迭代对象for循环') print('=============') for i in obj_iter: print(i)
大前提:生成器就是一种自定义的迭代器,本质就是迭代器
但凡函数内包含yield关键字,调用函数不会执行函数体代码,
会得到一个返回值,该返回值就是生成器对象
def func(): print('====1') yield 1 print('====2') yield 2 print('====3') yield 3 g = func() print(g) print(g is g.__iter__().__iter__()) g.__next__() res1 = next(g) # #会触发函数的执行,直到碰到一个yield停下来,并且将yield后的值当作本次next的结果返回 print(res1) res2 = next(g) print(res2) res3 = next(g) print(res3) # 生成器一般for连用 # for i in g: # print(i) # 总结yield:只能在函数内使用 #1. yield提供了一种自定义迭代器的解决方案 #2. yield可以保存函数的暂停的状态 #3. yield对比return # 1. 相同点:都可以返回值,值的类型与个数都没有限制 # 2. 不同点:yield可以返回多次值,而return只能返回一次值函数就结束了
''' 定义一个生成器,这个生成器可以生成10位斐波拉契数列,得到斐波拉契数列 # (斐波那契数列:数列中每一个数的值都等于前两个数相加的值 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55.........]) ''' def run(n): i, a, b = 0, 1, 1 while i < n: yield a a, b = b, a + b i += 1 for i in run(10): print(i)