生成器 补充知识点
*********************************昨日补充***********************************
- 生成器中的值会根据顺序一个一个的输出,当到最后一个yield输出后,生成器为空,再使用next取值将会报错,但使用for循环优化结果不会报错
- 生成器里面的值只有在用时才取
def fun(): yield 1 yield 2 yield 3 g=func() for i in g: print(i) #1,2,3 print(list(g)) #[] ################# def fun(): yield 1 yield 2 yield 3 g=func() for i in g: print(i) #1 print(list(g)) #[2,3]
*********************************今日内容***********************************
- 生成器中send()方法
- send(n)把生成器中的yield赋值成n,直到遇到下一个yield输出后,停止
- 注:在生成器开始使用时必须使用next方法,不能使用send
def func(): print(123) value=yield 1 # value=30
print(value) yield 2 print(456) yield 3 g=func() print(g.__next__()) #123,1 print(g.send(30)) # 30,2 print(g.__next__()) #456, 3
def average_func(): total=0 count=0 average=0 while True: value=yield average total+=value count+=1 average=total/count g=average_func() print(g.__next__()) #激活生成器 print(g.send(10)) #value=10 print(g.send(20)) #value=20 print(g.send(50)) #value=50
- 生成器预激活装饰器
def wapper(func): def inner(*args,**kwargs): g=func(*args,**kwargs) #g=average_func()
g.__next__()
return g
return inner @wapper def average_func(): total=0 count=0 average=0 while True: value=yield average total+=value count+=1 average=total/count g=average_func() print(g.send(10))
- 小结:
-send和next工作的起止位置是完全相同的
-send可以把一个值作为信号量传递到函数中去
-在生成器执行伊始,只能先用next
-只要用send传递参数的时候,必须在生成器中还有一个未被返回的yield
- 在send传入参数时生成器内部没有变量接受
def func(): print(1) yield 2 print(3) value = yield 4 print(5) yield value g = func() print(g.__next__()) #1,2 print(g.send(88)) #3,4 print(g.__next__()) #5,None
- 列表推导式与生成器表达式
- 列表推导式==列表表达式:为了简化代码,结果必须是个列表
#[1,3,5]==>[1,9,25]
new_l = [] for i in [1,3,5]: new_l.append(i*i) print(new_l) #[1,9,25] #列表表达式
print([i*i for i in [1,3,5]) #[1,9,25]
- 优缺点:优:方便简洁,缺:一次把生成列表,并写进内存中,占用内存大
- 生成器表达式:把列表推导式的[]换成()得到的就是生成器表达式
- 生成器表达式:sum(x ** 2 for x in range(4))
- 列表表达式:sum([x ** 2 for x in range(4)])
- 生成器表达式 (x ** 2 for x in range(4))
- 三种方法从生成器中取值,1.next方法;2.for ; 3.list强转
- 字典推导式
#字典中值与键对调 mcase = {'a':10,'b':34} print({mcase[i]:i for i in mcase}) # {10: 'a', 34: 'b'}
#合并大小写对应的value值,将k统一成小写
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3} new_dic ={k.lower():mcase.get(k.lower(),0)+mcase.get(k.upper(),0) for k in mcase} print(new_dic)
- 集合推导式
squared = {x**2 for x in [1, -1, 2]} print(squared) #set([1, 4])
- 生成器小结
- 把列表解析的[]换成()得到的就是生成器表达式
- 列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
- Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
sum(x ** 2 for x in range(4))
而不用多此一举的先构造一个列表:
sum([x ** 2 for x in range(4)])
- 生成器表达式类型于生成器函数,如果没有前面的赋值,是不产生生成器的,即下次调用还是新的开始,它与生成器函数很相似
g=(i for i in range(10)) print(list(g)) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(list(g)) # [] print(list(i for i in range(10))) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l = [i for i in range(0,15)] print(l) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] m = (i for i in range(0,15)) print(m) #<generator object <genexpr> at 0x104b6f258> for i in m: print(i,end=',') 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
注:不调用不会产生值,不调用不会产生值,不调用不会产生值