# Python 3.3新加了yield from语法
from itertools import chain # chain可以将迭代的类型给连接起来,直接做一个for循环
my_list = [1,2,3]
my_dict = {"Baidu":"http://www.baidu.com","Sohu":"http://www.sohu.com",
}for value in chain(my_list,my_dict,range(5,10)):print(value)
1
2
3
Baidu
Sohu
5
6
7
8
9
# Python 3.3新加了yield from语法
from itertools import chain # chain可以将迭代的类型给连接起来,直接做一个for循环
my_list = [1,2,3]my_dict = {"Baidu":"http://www.baidu.com","Sohu":"http://www.sohu.com",
}def my_chain(*args,**kwargs):  # 当传入的参数不确定是,用*argsfor my_iterable in args:   # args是tuple,属于可迭代对象for value in my_iterable:yield valuefor value in my_chain(my_list,my_dict,range(5,10)):print(value)

用my_chain函数,模拟实现chain的功能,发现有相同的效果。

# 用yield from实现
my_list = [1,2,3]my_dict = {"Baidu":"http://www.baidu.com","Sohu":"http://www.sohu.com",
}
# yield from 后面是iterable对象
def my_chain(*args,**kwargs):  # 当传入的参数不确定是,用*argsfor my_iterable in args:   # args是tuple,属于可迭代对象yield from my_iterablefor value in my_chain(my_list,my_dict,range(5,10)):print(value)

yield与yield from的区别

def g1(iterable):yield iterable  # yield,iterable是什么样子,输出就是什么样子。def g2(iterable):yield from iterable  # yield from会把iterable的每个值都给迭代出来for value in g1(range(10)):print(value)    # range(0, 10)for value in g2(range(10)):print(value)    # 0,1,2,3,4,5,6,7,8,9
range(0, 10)
0
1
2
3
4
5
6
7
8
9
# 用yield from实现
my_list = [1,2,3]my_dict = {"Baidu":"http://www.baidu.com","Sohu":"http://www.sohu.com",
}def my_chain(*args,**kwargs):for my_iterable in args:yield from my_iterablefor value in my_chain(my_list,my_dict,range(5,10)):print(value)def g1(gen):yield from gendef main():g = g1()g.send(None)#1. main为调用方。g1(委托生成器),gen(子生成器)
#1 yield from会在调用方main与子生成器gen之间建立一个双向通道。即yield执行完,将值直接交给main;甚至main生成的异常可以直接传递给gen
final_result = {}def sales_sum(pro_name):total = 0nums = []while True:x = yieldprint(pro_name+"销售: ",x)if not x:breaktotal += xnums.append(x)return total,numsdef middle(key):while True:final_result[key] = yield from sales_sum(key)print(key+"销售统计完成!!.")def main():data_sets = {"Tom-1牌面膜":[1200,1500,3000], # 销量"Tom-2牌手机": [200, 55, 98,108],"Tom-3牌大衣": [280, 560, 778,70]}for key,data_set in data_sets.items():print("start key:",key)m = middle(key)m.send(None) # 预激middle协程for vale in data_set:m.send(vale)  # 给协程传递每一组的值m.send(None)print("final result:",final_result)if __name__ == "__main__":main()
start key: Tom-1牌面膜
Tom-1牌面膜销售:  1200
Tom-1牌面膜销售:  1500
Tom-1牌面膜销售:  3000
Tom-1牌面膜销售:  None
Tom-1牌面膜销售统计完成!!.
start key: Tom-2牌手机
Tom-2牌手机销售:  200
Tom-2牌手机销售:  55
Tom-2牌手机销售:  98
Tom-2牌手机销售:  108
Tom-2牌手机销售:  None
Tom-2牌手机销售统计完成!!.
start key: Tom-3牌大衣
Tom-3牌大衣销售:  280
Tom-3牌大衣销售:  560
Tom-3牌大衣销售:  778
Tom-3牌大衣销售:  70
Tom-3牌大衣销售:  None
Tom-3牌大衣销售统计完成!!.
final result: {'Tom-1牌面膜': (5700, [1200, 1500, 3000]), 'Tom-2牌手机': (461, [200, 55, 98, 108]), 'Tom-3牌大衣': (1688, [280, 560, 778, 70])}
final_result = {}def sales_sum(pro_name):total = 0nums = []while True:x = yieldprint(pro_name+"销售: ",x)if not x:breaktotal += xnums.append(x)return total,numsif __name__ == "__main__":my_gen = sales_sum("Tom牌手机")my_gen.send(None) # 预激活my_gen.send(1200)my_gen.send(1500)my_gen.send(3000)try:my_gen.send(None)except StopIteration as e:result = e.valueprint(result)
Tom牌手机销售:  1200
Tom牌手机销售:  1500
Tom牌手机销售:  3000
Tom牌手机销售:  None
(5700, [1200, 1500, 3000])

pep380

关于 yeild from

1. RESULT = yield from EXPR可以简化成下面这样

一些说明

"""
_i:子生成器,同时也是一个迭代器
_y:子生成器生产的值_r:yield from 表达式最终的值
_s:调用方通过send()发送的值
_e:异常对象"""
_i = iter(EXPR) # EXPR是一个可迭代对象,_i其实是子生成器;
try:_y = next(_i) # 预激子生成器,把产出的第一个值存在_y中;
except StopIteration as _e:_r = _e.value # 如果抛出了StopIteration异常,那么就将异常对象的value属性保存到_r,这是最简单的情况的返回值;
else: while 1: # 尝试执行这个循环,委托生成器会阻塞;_s = yield _y # 生产子生成器的值,等待调用方send()值,发送过来的值将保存在_s中;try:_y = _i.send(_s) # 转发_s,并且尝试向下执行;except StopIteration as _e:_r = _e.value # 如果子生成器抛出异常,那么就获取异常对象的value属性存到_r,退出循环,恢复委托生成器的运行;break
RESULT = _r # _r就是整个yield from表达式返回的值。
"""子生成器可能只是一个迭代器,并不是一个作为协程的生成器,所以它不支持.throw()和.close()方法;如果子生成器支持.throw()和.close()方法,但是在子生成器内部,这两个方法都会抛出异常;调用方让子生成器自己抛出异常当调用方使用next()或者.send(None)时,都要在子生成器上调用next()函数,当调用方使用.send()发送非 None 值时,才调用子生成器的.send()方法;
"""
_i = iter(EXPR)
try:_y = next(_i)
except StopIteration as _e:_r = _e.value
else:while 1:try:_s = yield _yexcept GeneratorExit as _e:try:_m = _i.closeexcept AttributeError:passelse:_m()raise _eexcept BaseException as _e:_x = sys.exc_info()try:_m = _i.throwexcept AttributeError:raise _eelse:try:_y = _m(*_x)except StopIteration as _e:_r = _e.valuebreakelse:try:if _s is None:_y = next(_i)else:_y = _i.send(_s)except StopIteration as _e:_r = _e.valuebreak
RESULT = _r""" 看完代码,我们总结一下关键点:子生成器生产的值,都是直接传给调用方的;调用方通过.send()发送的值都是直接传递给子生成器的;如果发送的是 None,会调用子生成器的next()方法,如果不是 None,会调用子生成器的.send()方法;子生成器退出的时候,最后的return EXPR,会触发一个StopIteration(EXPR)异常;yield from表达式的值,是子生成器终止时,传递给StopIteration异常的第一个参数;如果调用的时候出现StopIteration异常,委托生成器会恢复运行,同时其他的异常会向上 "冒泡";传入委托生成器的异常里,除了GeneratorExit之外,其他的所有异常全部传递给子生成器的.throw()方法;如果调用.throw()的时候出现了StopIteration异常,那么就恢复委托生成器的运行,其他的异常全部向上 "冒泡";如果在委托生成器上调用.close()或传入GeneratorExit异常,会调用子生成器的.close()方法,没有的话就不调用。如果在调用.close()的时候抛出了异常,那么就向上 "冒泡",否则的话委托生成器会抛出GeneratorExit异常。"""

Python 高级编程和异步IO并发编程 --12_7 生成器进阶- yield from相关推荐

  1. Python 高级编程和异步IO并发编程 --13_5 ThreadPoolExecutor 和asyncio完成阻塞io请求

    # 使用多线程:在协程中集成阻塞io import asyncio import socket import time from urllib.parse import urlparse from c ...

  2. Python 高级编程和异步IO并发编程 --13_4 call_soon,call_at,call_soon_threadsafe

    import asynciodef callback(sleep_time):print("sleep {} success".format(sleep_time))if __na ...

  3. Python 高级编程和异步IO并发编程 --13_7 futur和task

    task是future的一个子类,task是协程和future之间的桥梁 task启动协程,保持和线程池的接口一致

  4. Python 高级编程和异步IO并发编程 --13_6 asyncio模拟http请求

    # asyncio 没有提供http协议的接口 import asyncio import time from urllib.parse import urlparseasync def get_ur ...

  5. Python学习笔记:异步IO(3)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  6. Python学习笔记:异步IO(2)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  7. 并发编程-初级之认识并发编程

    并发编程-初级之认识并发编程 1.并发领域可以处理的问题 分工: 同步:分好工之后,就可以具体执行.任务之间是有依赖的,一个任务结束之后将去去通知后续的任务.java里面 Executor.Fork/ ...

  8. akka mysql_Spray + Akka高性能异步IO并发

    Spray + Akka高性能异步IO并发 如何使用Java建立像Node.js那样非堵塞异步事件并发IO服务器呢?Spray是基于NIO2高并发框架,虽然Tomcat 8也是基于NIO2,但是Spa ...

  9. Python爬虫速度很慢?并发编程了解一下吧

    文章目录 前言 基础知识 GIL 多线程 创建Thread 对象 自定义类继承 Thread 私信小编01即可获取大量Python学习资源 前言 网络爬虫程序是一种智能 IO 密集型(页面请求,文件读 ...

最新文章

  1. ACCESS数据库防止下载
  2. 什么业务场景适合使用Redis?
  3. oracle rac应急_Support for Oracle RAC 框架资源组故障
  4. java中输入任意一个数 分别写出他个位 十位_Java 任意输入一个整数,求各个位数之和...
  5. Java面试题集锦,Java常见面试问题汇总,有需要的小伙伴看过来
  6. 根据map键值对,生成update与select语句,单条执行语句
  7. 石油计算机测控技术现场总线,中国石油北京《计算机测控技术》第二阶段在线作业...
  8. 学习单片机入门需要准备什么?
  9. EasyUI仓库管理系统
  10. python 实现抖音视频无水印解析
  11. 客户端第二次连接失败,SYN包发了,没有收到服务端回 SYN+ACK ,SYN包被丢弃了
  12. python斗地主游戏源码_Python实现的斗地主引擎
  13. 你真的了解Web Component吗?
  14. ubuntu怎么连网线上网_安装完ubuntu 16.04连接网线无法上网解决
  15. Linux、Windows、Mac非root普通用户使用秘钥免密SSH登录
  16. 网站头像上传(前台Ajax+后台PHP)
  17. PHP+MYSQL 可视化Echarts 完整源码,小白总结
  18. 手雷Android版 去广告,狂飙2MB/s 手雷(Android版迅雷)使用体验
  19. 维科精密IPO过会:年营收6.8亿 实控人陈燕来父女为外籍
  20. quectel(短消息服务命令)9

热门文章

  1. 基于javaweb的物业缴费管理系统(java+ssm+html+js+jsp+mysql)
  2. eclipse alt+←方向 快捷键失效-ikbc F108机械键盘的大坑
  3. 有一种美叫做思考——《编程之美》书评
  4. 旁路部署是什么?它是如何解决大型数据中心的DDOS防护问题的?
  5. Qt-OPCUA客户端
  6. 与或非c语言 同或 异或,与、或、非、与非、或非、异或、同或
  7. [初识]使用百度AI接口,图灵机器人实现简单语音对话
  8. 制作准考证的步骤,作业
  9. 怎么搭建一个易对接后台(包括网站源码及实例应用)
  10. sql排序规则,笔画,汉字,拼音,....(转载)