python异步编程 使用yield from过程解析


Posted in Python onSeptember 25, 2019

前言

yield from 是 Python3.3 后新加的语言结构。yield from的主要功能是打开双向通道,把最外层的调用方法与最内层的子生成器连接起来。这两者就可以进行发送值和返回值了,yeild from结构的本质是简化嵌套的生产器,不理解这个是什么意思的话,下面我将用几个例子来对其使用方法进行讲解。

yield from 是 Python3.3 后新加的语言结构。yield from的主要功能是打开双向通道,把最外层的调用方法与最内层的子生成器连接起来。这两者就可以进行发送值和返回值了,yeild from结构的本质是简化嵌套的生产器,不理解这个是什么意思的话,下面我将用几个例子来对其使用方法进行讲解。

简化for循环中的yeild

首先看一个

def gene():
 for c in 'AB':
  yield c #遇到yeild程序返回循环,下次从yeild后面开始。
 for i in range(3):
  yield i 
if __name__=="__main__":
 list(gene())#list内部会预激生成器

输出

['A','B','0','1', '2']

上面的代码可以简写成

def gene():
  yield from 'ab' 
  yield from range(3)
if __name__=="__main__":
 list(gene())

通过上面的代码我们可以知道,yield from 可以简化for循环里的yield表达式。当然yeild from的功能不仅仅是可以简化for循环而已,要是这样的话也就不值得,单独写一篇文章来介绍了。

我们仔细观察,简化后的式子有两个yeild from,同样的也就是说如果有10个for循环的yeild生成式,我们需要写10个yeild from,此时我们要记得在python中如果重复的代码出现了两次以及以上就该考虑优化了。好了接下来我们看一个优化后的例子。

通过yield from链接可迭代对象

def chain(*args):
 for i in args:
  # for m in i:
  # yield m
  yield from i
p = list(chain("1234", "AB", [1, 2, 3, 4, 5]))
print(p)

输出

['1', '2', '3', '4', 'A', 'B', 1, 2, 3, 4, 5]

这里对之前的例子做了个优化处理,通过*args可变参数,配合后面的for循环进行了多个可迭代对象的链接处理。下面来看一个复杂点的例子:

来自Python cookbook 3 ,github源码地址

https://github.com/dabeaz/python-cookbook/blob/master/src/4/how_to_flatten_a_nested_sequence/example.py)

扁平化处理嵌套型的数据

# Example of flattening a nested sequence using subgenerators

from collections import Iterable

def flatten(items, ignore_types=(str, bytes)):
 for x in items:
  if isinstance(x, Iterable) and not isinstance(x, ignore_types):
   yield from flatten(x)
  else:
   yield x

items = [1, 2, [3, 4, [5, 6], 7], 8]

# Produces 1 2 3 4 5 6 7 8
for x in flatten(items):
 print(x)

items = ['Dave', 'Paula', ['Thomas', 'Lewis']]
for x in flatten(items):
 print(x)

接下来通过说一下开篇提到的子生产器和调用方以及新的词委托生成器。

了解几个概念

yield from x 表达式对x对象做的第一件事是,调用 iter(x),从中获取一个迭代器。所以x是可迭代对象。上面的例子中的x如果是可迭代对象就会执行,yield from flatten(x).

PEP380 的标题是 ”syntax for delegating to subgenerator“(把指责委托给子生成.器的句法)。由此我们可以知道,yield from是可以实现嵌套生成器的使用。

yield from在看接下来的代码之前我们必须知道这几个概念:

委派生成器

包含yield from 表达式的生成器函数

子生成器

从yield from 部分获取的生成器,含义yield的。

调用方

调用委派生成器的客户端(调用方)代码,也就是运行入口。

ok,了解了这些我们看接下来的一个例子。

使用yeild from写一个异步爬虫

import requests
from collections import namedtuple ①
Response = namedtuple("rs", 'url status') ②
# 子生产器
def fecth(): ③
 res=[]
 while 1:
  url = yield ④
  if url is None: ⑤
   break
  req = requests.get(url)
  res.append(Response(url=url, status=req.status_code))
 return res

#委派生成器
def url_list(l, key):
 while 1: ⑥
  l[key] = yield from fecth() ⑦

#调用方
def main():
 l = {}
 u = ["http://www.baidu.com", "http://www.cnblogs.com"]
 for index, url in enumerate(u):
  if index == 0:
   ul = url_list(l, index)
   next(ul) ⑧
  ul.send(url)⑨
 ul.send(None)⑩
 return l
if __name__ == '__main__':
 res = main()
 print(res)

接下来对上面的标准进行解释:

① 引入一个具名元组,可以后面实现一个简单的类。

② 对请求参数做一个格式化处理,后面通过获取属性即可。

③一个协程,通过requests模块可以发起网络请求。

④main函数的发送的值绑定到这里的url上

⑤ url为None即没有url的时候结束循环的。

⑥这个循环每次都会新建一个fetch 实例,每个实例都是作为协程使用的生成器对象。

⑦ url_list发送的每个值都会经由yield from 处理,然后传给fetch 实例。url_list会在yield from表达式处暂停,等待fetch实例处理客户端发来的值。fetch实例运行完毕后,返回的值绑定到l[key] 上。while 循环会不断创建fetch实例,处理更多的值。

⑧激活url_list生成器⑨把各个url以及其序列号index,传给url_list传入的值最终到达fetch函数中,url_list并不知道传入的是什么,同时url_list实例在yield from处暂停。直到fetch的一个实例处理完才进行赋值。

⑩关键的一步,# 把None传入url_list,传入的值最终到达fetch函数中,导致当前实例终止。然后继续创建下一个实例。如果没有ul.send(None),那么fetch子生成器永远不会终止,因为ul.send()发送的值实际是在fetch实例中进行,委派生成器也永远不会在此激活,也就不会为l[key]赋值

参考资料:

流畅的python 第16章 PEP 380-- Syntax for Delegating to a Subgenerator How Python 3.3 "yield from" construct works

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
详解Python中heapq模块的用法
Jun 28 Python
Python随机生成均匀分布在单位圆内的点代码示例
Nov 13 Python
Python利用pandas计算多个CSV文件数据值的实例
Apr 19 Python
Python PyQt4实现QQ抽屉效果
Apr 20 Python
Python Series从0开始索引的方法
Nov 06 Python
python装饰器简介---这一篇也许就够了(推荐)
Apr 01 Python
pytorch索引查找 index_select的例子
Aug 18 Python
pytorch中的自定义反向传播,求导实例
Jan 06 Python
python 命名规范知识点汇总
Feb 14 Python
pytorch使用tensorboardX进行loss可视化实例
Feb 24 Python
Python selenium的这三种等待方式一定要会!
Jun 10 Python
python的变量和简单数字类型详解
Sep 15 Python
手机使用python操作图片文件(pydroid3)过程详解
Sep 25 #Python
Python缓存技术实现过程详解
Sep 25 #Python
Laravel框架表单验证格式化输出的方法
Sep 25 #Python
pyqt5 QScrollArea设置在自定义侧(任何位置)
Sep 25 #Python
python 用户交互输入input的4种用法详解
Sep 24 #Python
python getpass实现密文实例详解
Sep 24 #Python
使用Python的turtle模块画国旗
Sep 24 #Python
You might like
PHP 编程请选择正确的文本编辑软件
2006/12/21 PHP
php递归创建和删除文件夹的代码小结
2012/04/13 PHP
ThinkPHP 3.2 版本升级了哪些内容
2015/03/05 PHP
PHP微信支付实例解析
2016/07/22 PHP
ext checkboxgroup 回填数据解决
2009/08/21 Javascript
js 弹出框 替代浏览器的弹出框
2010/10/29 Javascript
jquery插件制作 提示框插件实现代码
2012/08/17 Javascript
用客户端js实现带省略号的分页
2013/04/27 Javascript
A标签触发onclick事件而不跳转的多种解决方法
2013/06/27 Javascript
js 三级关联菜单效果实例
2013/08/13 Javascript
JavaScript中的变量作用域介绍
2014/12/31 Javascript
AngularJS表单编辑提交功能实例
2015/02/13 Javascript
JavaScript中的getTime()方法使用详解
2015/06/10 Javascript
Vue自定义指令详解
2017/07/28 Javascript
基于node.js的fs核心模块读写文件操作(实例讲解)
2017/09/10 Javascript
react-native-video实现视频全屏播放的方法
2018/03/19 Javascript
js逆向解密之网络爬虫
2019/05/30 Javascript
jQuery实现计算器功能
2020/10/19 jQuery
Python中atexit模块的基本使用示例
2015/07/08 Python
Python 获取中文字拼音首个字母的方法
2018/11/28 Python
Python实现的爬取百度文库功能示例
2019/02/16 Python
pyqt5 键盘监听按下enter 就登陆的实例
2019/06/25 Python
Django Channels 实现点对点实时聊天和消息推送功能
2019/07/17 Python
html5中的input新属性range使用记录
2014/09/05 HTML / CSS
Blue Nile台湾:钻石珠宝商,订婚首饰、结婚戒指和精品首饰
2017/11/24 全球购物
拉飞逸官网:Lafayette 148 New York
2020/07/15 全球购物
如何获得EntityManager
2014/02/09 面试题
酒吧员工的岗位职责
2013/11/26 职场文书
四年级下册教学反思
2014/02/01 职场文书
《故都的秋》教学反思
2014/04/15 职场文书
2014年光棍节活动策划方案(创意集锦)
2014/09/29 职场文书
小升初自荐信怎么写
2015/03/26 职场文书
安全生产警示教育活动总结
2015/05/09 职场文书
侵犯商业秘密的律师函
2015/05/27 职场文书
创业计划书之游泳馆
2019/09/16 职场文书
前端canvas中物体边框和控制点的实现示例
2022/08/05 Javascript