一、迭代器
如何从列表、字典中取值的:
1)index索引 ,key,前提必须知道索引或key值才能取到对应的value
2)for循环
凡是可以使用for循环取值的都是可迭代的
可迭代协议 :内部含有__iter__方法的都是可迭代的
迭代器协议 :内部含有__iter__方法和__next__方法的都是迭代器
1 print(dir([1,2,3])) 2 #>>>['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] 3 lst_iter = [1,2,3].__iter__() 4 print(lst_iter.__next__())#>>>1 5 print(lst_iter.__next__())#>>>2 6 print(lst_iter.__next__())#>>>3 7 8 #上面代码相当于for循环取值 9 for i in [1,2,3]: # 使用for循环时,在内部调用__iter__方法,变成迭代器。[1,2,3].__iter__() 10 print(i) 11 12 #使用while循环实现for循环的机制 13 l = [1,2,3] 14 lst_iter = iter(l) # iter(l)相当于l.__iter__(),都是产生一个迭代器 15 while True: 16 try: 17 print(next(lst_iter)) # next(lst_iter)相当于lst_iter.__next__() 18 except StopIteration: 19 break 20 21 # 什么是可迭代的 22 # 什么是迭代器 迭代器 = iter(可迭代的),自带一个__next__方法 23 # 可迭代 最大的优势 节省内存 24 25 #例:以下是python3运行的结果 26 from collections import Iterable,Iterator 27 print(range(100000000)) 28 print(isinstance(range(100000000),Iterable))#判断是不是可迭代的 29 print(isinstance(range(100000000),Iterator))#判断是不是迭代器 30 # >>>range(0, 100000000) 31 # >>>True 32 # >>>False 33 34 # python2 range 不管range多少 会生成一个列表 这个列表将用来存储所有的值 35 # python3 range 不管range多少 都不会实际的生成任何一个值 36 # 迭代器的优势: 37 # 节省内存 38 # 取一个值就能进行接下来的计算 ,而不需要等到所有的值都计算出来才开始接下来的运算 —— 快 39 # 迭代器的特性:惰性运算 40 41 #例 42 f = open() 43 for line in f:#用一行读一行 44 45 # 可迭代对象:列表 字典 元组 字符串 集合 range 文件句柄 enumerate(加序号)
二、生成器
生成器 Generator
自己写的迭代器 就是一个生成器
两种自己写生成器(迭代器)的机制:生成器函数 生成器表达式
1、生成器函数
1 # 凡是带有yield的函数就是一个生成器函数 2 def func(): 3 print('****') 4 yield 1 5 print('^^^^') 6 yield 2 # 记录当前所在的位置,等待下一次next来触发函数的状态 7 8 g = func() 9 print('--',next(g)) 10 #>>>**** 11 #>>>-- 1 12 print('--',next(g)) 13 #>>>^^^^ 14 #>>>-- 2
例1:
# 需要定制200 0000件衣服 # 承包:牛翔 一起做完200 0000才进行反馈,这时候已经开到40期了 # 承包:赵英杰 200 0000,你每一期需要的时候才进行生产和反馈 def cloth(num): ret = [] for i in range(num): ret.append('cloth%s'%i) return ret ret=cloth(10) print(ret)#>>>['cloth0', 'cloth1', 'cloth2', 'cloth3', 'cloth4', 'cloth5', 'cloth6', 'cloth7', 'cloth8', 'cloth9'] # 想要生成器函数执行,需要用next def cloth_g(num): for i in range(num): yield 'cloth%s'%i g = cloth_g(1000) print(next(g))#>>>cloth0 print(next(g))#>>>cloth1 print(next(g))#>>>cloth2
例2:使用生成器监听文件输入的例子
1 #在mac系统上不能直接操作文件,需要关闭或使用程序写入文件 2 import time 3 def listen_file(): 4 with open('userinfo') as f: 5 while True: 6 line = f.readline() 7 if line.strip(): 8 yield line.strip() 9 time.sleep(0.1) 10 11 g = listen_file() 12 for line in g: 13 print(line)
例3:send关键字
1 def func(): 2 print(11111) 3 ret1 = yield 1 4 print(22222,'ret1 :',ret1) 5 ret2 = yield 2 6 print(33333,'ret2 :',ret2) 7 yield 3 8 9 g = func() 10 ret = next(g)#第一次使用生成器时不能用send执行 11 print(ret) 12 #>>>11111 13 #>>>1 14 print(g.send('alex')) # 在执行next的过程中 传递一个参数 给生成器函数的内部 15 #>>>22222 ret1 : alex 16 #>>>2 17 print(g.send('金老板')) 18 #>>>33333 ret2 : 金老板 19 #>>>3
备注:向生成器中传递值 有一个激活的过程 第一次必须要用next触发这个生成器
例4:计算移动平均值
1 # 计算移动平均值 2 # 月度 的 天平均收入 3 def average(): 4 sum_money = 0 5 day = 0 6 avg = 0 7 while True: 8 money = yield avg 9 sum_money += money 10 day += 1 11 avg = sum_money/day 12 13 g = average() 14 next(g)#得到一个0 15 print(g.send(200))#>>>200.0 16 print(g.send(300))#>>>250.0 17 print(g.send(600))#>>>366.6666666666667
2、预激生成器
作用:当程序中的多个函数都需要预激活,那么就可以交给装饰器来解决
1 def init(func): 2 def inner(*args,**kwargs): 3 ret = func(*args,**kwargs) 4 next(ret) # 预激活 5 return ret 6 return inner 7 8 @init 9 def average(): 10 sum_money = 0 11 day = 0 12 avg = 0 13 while True: 14 money = yield avg 15 sum_money += money 16 day += 1 17 avg = sum_money/day 18 19 g = average() 20 print(g.send(200)) 21 print(g.send(300)) 22 print(g.send(600))
3、yield from (python3中的用法)
1 def generator_func(): 2 yield from range(5) 3 yield from 'hello' 4 #与下列代码相同 5 # for i in range(5): 6 # yield i 7 # for j in 'hello': 8 # yield j 9 10 g = generator_func() 11 for i in generator_func():#与for i in g:相同 12 print(i) 13 14 g = generator_func() 15 while True: 16 print(generator_func())#会报错,每一次执行此函数都会生成一个新的生成器 17 g1 = generator_func() 18 g2 = generator_func() 19 next(generator_func()) 20 next(generator_func())
4、如何从生成器中取值
1 # 第一种 :next 随时都可以停止 最后一次会报错 2 print(next(g)) 3 print(next(g)) 4 # 第二种 :for循环 从头到尾遍历一次 不遇到break、return不会停止 5 for i in g: 6 print(i) 7 # 第三种 :list tuple 数据类型的强转 会把所有的数据都加载到内存里 非常的浪费内存 8 print(g) 9 print(list(g))
5、总结
1 # 生成器函数 是我们python程序员实现迭代器的一种手段 2 # 主要特征是 在函数中 含有yield 不建议使用return 3 # 调用一个生成器函数 不会执行这个函数中的带码 只是会获得一个生成器(迭代器) 4 # 只有从生成器中取值的时候,才会执行函数内部的带码,且每获取一个数据才执行得到这个数据的带码 5 # 获取数据的方式包括 next send 循环 数据类型的强制转化 6 # yield返回值的简便方法,如果本身就是循环一个可迭代的,且要把可迭代数据中的每一个元素都返回 可以用yield from 7 # 使用send的时候,在生成器创造出来之后需要进行预激,这一步可以使用装饰器完成 8 # 生成器的特点 : 节省内存 惰性运算 9 # 生成器用来解决 内存问题 和程序功能之间的解耦 10 #解耦:将功能性的代码进行尽量拆分,提交代码可读性,复用性
三、生成器表达式
1 # 列表推倒式 2 #求平方,然后存放到列表中 3 #方式1 4 new_lst = [] 5 for i in range(10): 6 new_lst.append(i**2) 7 print(new_lst) 8 #方式2 9 print([i**2 for i in range(10)]) 10 #求2的余数,然后存放放列表中 11 l = [1,2,3,-5,6,20,-7] 12 print([i%2 for i in range(10)]) 13 #找出所有的奇数,然后存放放列表中 14 l = [1,2,3,-5,6,20,-7] 15 print([num for num in l if num%2 == 1]) 16 17 # 30以内所有能被3整除的数 18 print([i for i in range(30) if i%3 ==0]) 19 20 # 30以内所有能被3整除的数的平方 21 print([i**2 for i in range(30) if i%3 ==0]) 22 23 # 找到嵌套列表中名字含有两个‘e’的所有名字 24 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], 25 ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] 26 print([name for name_lst in names for name in name_lst if name.count('e') == 2]) 27 28 # 生成器表达式 29 l = [i for i in range(30) if i%3 ==0] # 列表推倒式 排序的时候 30 g = (i for i in range(30) if i%3 ==0) # 生成器表达式 庞大数据量的时候 使用生成器表达式 31 print(l)#>>>[0, 3, 6, 9, 12, 15, 18, 21, 24, 27] 32 print(g)#>>><generator object <genexpr> at 0x000002A16630B8E0> 33 for i in g:print(i)
四、面试题
1 # 面试题1 2 # def demo(): 3 # for i in range(4): 4 # yield i 5 # 6 # g=demo() 7 # 8 # g1=(i for i in g) 9 # g2=(i for i in g1) 10 # 11 # print(list(g1))#>>>[0, 1, 2, 3] 12 # print(list(g2))#>>>[] 13 14 15 # 面试题2 16 # def add(n,i): 17 # return n+i 18 # 19 # 20 # def test(): 21 # for i in range(4): 22 # yield i 23 # 24 # g=test() 25 # for n in [1,10]: 26 # g=(add(n,i) for i in g) 27 # 28 # print(list(g))#>>>[20, 21, 22, 23] 29 30 31 # 一个生成器 只能取一次 32 # 生成器在不找它要值的时候始终不执行 33 # 当他执行的时候,要以执行时候的所有变量值为准