迭代器和生成器
迭代器和生成器
1. 可迭代对象
1 # 迭代 2 迭代即更新换代 每次的更新都必须依赖于上一次的结果 3 4 '''迭代其实给我们提供了一种不依赖索引取值的方式''' 5 6 # 可迭代对象 7 内置有__iter__方法的都称之为可迭代对象 8 内置的意思是可以通过点的方式直接查看到的 9 """ 10 针对双下滑线开头 双下滑线结尾的方法 最为专业标准的读法为 11 双下方法名 12 13 面向对象的时候为了与隐藏变量区分开 14 """ 15 16 # n = 1 17 # while True: 18 # n+=1 19 # print(n) 20 21 # l = [11,22,33,44,55,66] 22 # n = 0 23 # while n < len(l): 24 # print(l[n]) 25 # n += 1 26 27 i = 12 # 没有 28 f = 11.11 # 没有 29 s = 'jason' # 有 30 l = [111,22,33,4] # 有 31 d = {'username':'jason','pwd':123} # 有 32 t = (11,22,33) # 有 33 se = {11,22,33} # 有 34 b = True # 没有 35 # file = open(r'a.txt','w',encoding='utf8') 36 """ 37 含有__iter__的有 38 字符串 列表 字典 元组 集合 文件对象 39 上述通常为可迭代对象 40 """ 41 print(d) 42 print(d.__iter__()) # 等价于调用了一个内置方法 d.get() 43 print(iter(d)) 44 print(d.__len__()) 45 print(len(d)) 46 """ 47 可迭代对象调用__iter__方法会变成迭代器对象(老母猪) 48 49 __iter__方法在调用的时候还有一个简便的写法iter() 50 一般情况下所有的双下方法都会有一个与之对应的简化版本 方法名() 51 """
2. 迭代器对象
1 """ 2 迭代器对象 3 即含有__iter__方法 又含有__next__方法 4 如何生成迭代器对象 5 让可迭代对象执行__iter__方法 6 7 文件对象本身即是可迭代对象又是迭代器对象 8 迭代器对象无论执行多少次__iter__方法 还是迭代器对象(本身) 9 10 迭代器给我们提供了不依赖于索引取值的方式 11 """ 12 i = 12 # 没有 13 f = 11.11 # 没有 14 s = 'jason' # 有 15 l = [111,222,333,444] # 有 16 d = {'username':'jason','pwd':123} # 有 17 t = (11,22,33) # 有 18 se = {11,22,33} # 有 19 b = True # 没有 20 file = open(r'a.txt','w',encoding='utf8') 21 22 # res = s.__iter__() # 转成迭代器对象 23 # print(res.__next__()) # 迭代器对象执行__next__方法其实就是在迭代取值(for循环) 24 # print(res.__next__()) 25 # print(res.__next__()) 26 # print(res.__next__()) 27 # print(res.__next__()) 28 29 30 # res = d.__iter__() # 转成迭代器对象 31 # print(res.__next__()) # 迭代器对象执行__next__方法其实就是在迭代取值(for循环) 32 # print(res.__next__()) 33 # print(res.__next__()) # 取完元素之后再取会"报错" 34 35 # 易错 36 # print(d.__iter__().__next__()) # username 37 # print(d.__iter__().__next__()) # username 38 # print(d.__iter__().__next__()) # username 39 # print(d.__iter__().__next__()) # username 40 # print(d.__iter__().__next__()) # username 41 # print(d.__iter__().__next__()) # username
3. 生成器
3.1 生成器对象
1 """ 2 生成器其实就是自定义迭代器 3 """ 4 # 定义阶段就是一个普通函数 5 def my_ge(): 6 print('first') 7 yield 123,222,333 8 print('second') 9 # yield 456,444,555 10 """ 11 当函数体内含有yield关键字 那么在第一次调用函数的时候 12 并不会执行函数体代码 而是将函数变成了生成器(迭代器) 13 """ 14 # 调用函数:不执行函数体代码 而是转换为生成器(迭代器) 15 # res = my_ge() 16 # ret = res.__next__() # 每执行一个__next__代码往下运行到yield停止 返回后面的数据 17 # print(ret) 18 # ret = res.__next__() # 再次执行__next__接着上次停止的地方继续往后 遇到yield再停止 19 # print(ret)
3.2 yield传值
1 def eat(name): 2 print('%s 准备干饭!!!'%name) 3 while True: 4 food = yield 5 print('%s 正在吃 %s' % (name, food)) 6 res = eat('jason') # 并不会执行代码 而是转换成生成器 7 res.__next__() 8 res.send('肉包子') 9 res.send('盖浇饭')
3.3 yield和return的对比
1 yield 2 1.可以返回值(支持多个并且组织成元组) 3 2.函数体代码遇到yield不会结束而是"停住" 4 3.yield可以将函数变成生成器 并且还支持外界传值 5 return 6 1.可以返回值(支持多个并且组织成元组) 7 2.函数体代码遇到return直接结束
3.4 生成器表达式
l = [11, 22, 33, 44, 55, 66, 77, 88, 99] # res = [i+1 for i in l if i!=44] # print(res) # res1 = (i+1 for i in l if i!=44) """ 生成器表达式内部的代码只有在迭代取值的时候才会执行 """ # print(res1.__next__()) # print(res1.__next__()) # print(res1.__next__()) """ 迭代器对象 生成器对象 我们都可以看成是"工厂" 只有当我们所要数据的时候工厂才会加工出"数据" 上述方式就是为了节省空间 """ # 求和 def add(n, i): return n + i # 调用之前是函数 调用之后是生成器 def test(): for i in range(4): yield i g = test() # 初始化生成器对象 for n in [1, 10]: g = (add(n, i) for i in g) """ 第一次for循环 g = (add(n, i) for i in g) 第二次for循环 g = (add(10, i) for i in (add(10, i) for i in g)) """ res = list(g) print(res) #A. res=[10,11,12,13] #B. res=[11,12,13,14] #C. res=[20,21,22,23] #D. res=[21,22,23,24]