def gen(): """子生成器""" yield 1 def gen1(gen): """委托生成器""" yield from gen def main(): """调用方""" g = gen() g1 = gen1(g) g1.send(None) # 启动生成器
上面的代码有3个角色, main是调用方. gen1:委托生成器, gen:子生成器
yield from会在调用方与子生成器之间建立一个双方通道, 这样,调用方和子生成器之间就可以进行通信(send, close , throw )
示例
final_result = {} def sales_num(key): total = 0 nums = [] while True: x = yield # 使用while循环不断的从调用方接收值 print(key + '销量:', x) if not x: break # 结束while循环 total += x nums.append(x) return total, nums # 生成器的值返回到delegate委托生成器中 def delegate(key): """委托生成器""" while True: final_result[key] = yield from sales_num(key) print(key + '销量统计完成') def main(): data_set = { "欧莱雅": [100, 200, 400], "法泉": [12, 4354, 67], "死贵人": [212, 23423, 545] } for key, data in data_set.items(): print('start key:', key) d = delegate(key) d.send(None) for value in data: d.send(value) # 这儿是直接将值send到sales_num子生成器中 d.send(None) # 结果一个key的统计 print('final_result:', final_result) if __name__ == '__main__': main()
打印:
start key: 欧莱雅 欧莱雅销量: 100 欧莱雅销量: 200 欧莱雅销量: 400 欧莱雅销量: None 欧莱雅销量统计完成 start key: 法泉 法泉销量: 12 法泉销量: 4354 法泉销量: 67 法泉销量: None 法泉销量统计完成 start key: 死贵人 死贵人销量: 212 死贵人销量: 23423 死贵人销量: 545 死贵人销量: None 死贵人销量统计完成 final_result: {'欧莱雅': (700, [100, 200, 400]), '法泉': (4433, [12, 4354, 67]), '死贵人': (24180, [212, 23423, 545])}
补充
def sales_num(key): """定义一个生成器""" total = 0 nums = [] while True: x = yield print(key + '销量:', x) if not x: break # 结束while循环 total += x nums.append(x) return total, nums if __name__ == '__main__': g = sales_num("苹果手机") g.send(None) # 激活生成器, 也可以使用next(g) g.send(5000) # send一个值到生成器内部, 就是x接收的 g.send(1000) # send一个值到生成器内部, 就是x接收的 g.send(5000) # send一个值到生成器内部, 就是x接收的 g.send(None) # 这次send(None) 表过结束生成器,生成器会抛出StopIteration异常,这是个正常的异常,然后返回total, nums
Traceback (most recent call last): 苹果手机销量: 5000 File "E:/ws/python/LearnFlask/test/mooic/yield_test.py", line 21, in <module> 苹果手机销量: 1000 g.send(None) 苹果手机销量: 5000 StopIteration: (11000, [5000, 1000, 5000]) 苹果手机销量: None
为了优雅的结束生成器, 需要try .... StopIteration....
下面是优雅的结束生成器的代码
def sales_num(key): """定义一个生成器""" total = 0 nums = [] while True: x = yield print(key + '销量:', x) if not x: break # 结束while循环 total += x nums.append(x) return total, nums if __name__ == '__main__': g = sales_num("苹果手机") g.send(None) # 激活生成器, 也可以使用next(g) g.send(5000) # send一个值到生成器内部, 就是x接收的 g.send(1000) # send一个值到生成器内部, 就是x接收的 g.send(5000) # send一个值到生成器内部, 就是x接收的 try: g.send(None) # 这次send(None) 表过结束生成器,生成器会抛出StopIteration异常,这是个正常的异常,然后返回total, nums except StopIteration as e: print(e.value) # (11000, [5000, 1000, 5000]) 通过异常,获取生成器的返回值
苹果手机销量: 5000 苹果手机销量: 1000 苹果手机销量: 5000 苹果手机销量: None (11000, [5000, 1000, 5000])
通过上面的yield from示例可知,yield from帮我们处理了try...stopiteration...异常, 因为我们并没有手动去处理.
日拱一卒无有尽,功不唐捐终入海