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 23 Python
python端口扫描系统实现方法
Nov 19 Python
Python实现基本线性数据结构
Aug 22 Python
在Pycharm中对代码进行注释和缩进的方法详解
Jan 20 Python
Python3.4学习笔记之类型判断,异常处理,终止程序操作小结
Mar 01 Python
Django给admin添加Action的步骤详解
May 01 Python
python绘制已知点的坐标的直线实例
Jul 04 Python
python多线程扫描端口(线程池)
Sep 04 Python
pytorch中获取模型input/output shape实例
Dec 30 Python
Python对称的二叉树多种思路实现方法
Feb 28 Python
Python实现文件压缩和解压的示例代码
Aug 12 Python
Selenium 安装和简单使用的实现
Dec 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
浅谈Windows下 PHP4.0与oracle 8的连接设置
2006/10/09 PHP
基于Linux调试工具strace与gdb的常用命令总结
2013/06/03 PHP
mod_php、FastCGI、PHP-FPM等PHP运行方式对比
2015/07/02 PHP
PHP编写学校网站上新生注册登陆程序的实例分享
2016/03/21 PHP
Centos7安装swoole扩展操作示例
2020/03/26 PHP
Ruffy javascript 学习笔记
2009/11/30 Javascript
JQuery 绑定select标签的onchange事件,弹出选择的值,并实现跳转、传参
2011/01/06 Javascript
jquery用ajax方式从后台获取json数据后如何将内容填充到下拉列表
2015/08/26 Javascript
浅析Bootstrap缩略图组件与警示框组件
2016/04/29 Javascript
原生JS实现轮播效果+学前端的感受(防止走火入魔)
2016/08/21 Javascript
JavaScript实现使用Canvas绘制图形的基本教程
2016/10/27 Javascript
JavaScript浏览器对象模型BOM(BrowserObjectModel)实例详解
2016/11/29 Javascript
vue.js的双向数据绑定Object.defineProperty方法的神奇之处
2019/01/18 Javascript
富文本编辑器vue2-editor实现全屏功能
2019/05/26 Javascript
[02:12]打造更好的电竞完美世界:完美盛典回顾篇
2018/12/19 DOTA
python网络编程学习笔记(七):HTML和XHTML解析(HTMLParser、BeautifulSoup)
2014/06/09 Python
Python中死锁的形成示例及死锁情况的防止
2016/06/14 Python
Linux上安装Python的PIL和Pillow库处理图片的实例教程
2016/06/23 Python
Python微信库:itchat的用法详解
2017/08/14 Python
Python将DataFrame的某一列作为index的方法
2018/04/08 Python
使用python画个小猪佩奇的示例代码
2018/06/06 Python
python2 与 python3 实现共存的方法
2018/07/12 Python
python实现二分类的卡方分箱示例
2019/11/22 Python
jupyter notebook 多行输出实例
2020/04/09 Python
你可能不熟练的十个前端HTML5经典面试题
2018/07/03 HTML / CSS
雪花秀美国官方网站:韩国著名草本护肤化妆品品牌
2016/10/19 全球购物
FitFlop澳大利亚官网:英国符合人体工学的鞋类品牌
2017/06/05 全球购物
鞋类设计与工艺专业销售求职信
2013/11/01 职场文书
音乐教学反思
2014/02/02 职场文书
鲜花方阵解说词
2014/02/13 职场文书
关于安全的演讲稿
2014/05/09 职场文书
志愿者宣传口号
2014/06/17 职场文书
优秀纪检干部材料
2014/08/27 职场文书
python 自动化偷懒的四个实用操作
2021/04/11 Python
Python爬虫框架之Scrapy中Spider的用法
2021/06/28 Python
Python&Matlab实现灰狼优化算法的示例代码
2022/03/21 Python