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中取整的几种方法小结
Jan 06 Python
Python3实现发送QQ邮件功能(html)
Dec 15 Python
python re模块findall()函数实例解析
Jan 19 Python
Python并发:多线程与多进程的详解
Jan 24 Python
利用python3 的pygame模块实现塔防游戏
Dec 30 Python
Python Selenium安装及环境配置的实现
Mar 17 Python
python手机号前7位归属地爬虫代码实例
Mar 31 Python
Python+PyQt5实现灭霸响指功能
May 25 Python
一些关于python 装饰器的个人理解
Aug 31 Python
Python实现加密的RAR文件解压的方法(密码已知)
Sep 11 Python
Python json解析库jsonpath原理及使用示例
Nov 25 Python
python 进阶学习之python装饰器小结
Sep 04 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
dede3.1分页文字采集过滤规则详说(图文教程)续四
2007/04/03 PHP
使用PHP获取当前url路径的函数以及服务器变量
2013/06/29 PHP
PHP 如何利用phpexcel导入数据库
2013/08/24 PHP
使用php检测用户当前使用的浏览器是否为IE浏览器
2013/12/03 PHP
PHP读MYSQL中文乱码的快速解决方法
2016/10/01 PHP
PHP如何读取由JavaScript设置的Cookie
2017/03/22 PHP
PHP实践教程之过滤、验证、转义与密码详解
2017/07/24 PHP
jquery 使用简明教程
2014/03/05 Javascript
兼容Firefox的Javascript XSLT 处理XML文件
2014/12/31 Javascript
JavaScript分秒倒计时器实现方法
2015/02/02 Javascript
JavaScript中iframe实现局部刷新的几种方法汇总
2016/01/06 Javascript
jQuery获得字体颜色16位码的方法
2016/02/20 Javascript
JavaScript与java语言有什么不同
2016/09/22 Javascript
JS实现的系统调色板完整实例
2016/12/21 Javascript
微信小程序图片选择区域裁剪实现方法
2017/12/02 Javascript
Linux Centos7.2下安装nodejs&npm配置全局路径的教程
2018/05/15 NodeJs
jQuery实现点击自身以外区域关闭弹出层功能完整示例【改进版】
2018/07/31 jQuery
Vue插件打包与发布的方法示例
2018/08/20 Javascript
JavaScript强制类型转换和隐式类型转换操作示例
2019/05/01 Javascript
layui给下拉框、按钮状态、时间赋初始值的方法
2019/09/10 Javascript
vue使用showdown并实现代码区域高亮的示例代码
2019/10/17 Javascript
Vue ​v-model相关知识总结
2021/01/28 Vue.js
[38:30]2014 DOTA2国际邀请赛中国区预选赛 LGD-GAMING VS CIS 第一场2
2014/05/24 DOTA
详解Python的Flask框架中生成SECRET_KEY密钥的方法
2016/06/07 Python
python tensorflow学习之识别单张图片的实现的示例
2018/02/09 Python
python 实现手机自动拨打电话的方法(通话压力测试)
2019/08/08 Python
Python2比较当前图片跟图库哪个图片相似的方法示例
2019/09/28 Python
python 中值滤波,椒盐去噪,图片增强实例
2019/12/18 Python
深入浅析Python 命令行模块 Click
2020/03/11 Python
详解python中GPU版本的opencv常用方法介绍
2020/07/24 Python
大宝sod蜜广告词
2014/03/21 职场文书
先进个人申报材料
2014/12/30 职场文书
长城英文导游词
2015/01/30 职场文书
地道战观后感2000字
2015/06/04 职场文书
go xorm框架的使用
2021/05/22 Golang
CSS巧用渐变实现高级感背景光动画
2021/12/06 HTML / CSS