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

前言

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

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

(0)

相关推荐

  • Python的Twisted框架上手前所必须了解的异步编程思想

    前言 最近有人在Twisted邮件列表中提出诸如"为任务紧急的人提供一份Twisted介绍"的需求.值得提前透露的是,这个系列并不会如他们所愿.尤其是介绍Twisted框架和基于Python 的异步编程而言,可能短时间无法讲清楚.因此,如果你时间紧急,这恐怕不是你想找的资料. 我相信如果对异步编程模型一无所知,快速的介绍同样无法让你对其有所理解,至少你得稍微懂点基础知识吧.我已经用Twisted框架几年了,因此思考过我当初是怎么学习它(学得很慢)并发现学习它的最大难度并不在Twiste

  • python并发编程之多进程、多线程、异步和协程详解

    最近学习python并发,于是对多进程.多线程.异步和协程做了个总结. 一.多线程 多线程就是允许一个进程内存在多个控制权,以便让多个函数同时处于激活状态,从而让多个函数的操作同时运行.即使是单CPU的计算机,也可以通过不停地在不同线程的指令间切换,从而造成多线程同时运行的效果. 多线程相当于一个并发(concunrrency)系统.并发系统一般同时执行多个任务.如果多个任务可以共享资源,特别是同时写入某个变量的时候,就需要解决同步的问题,比如多线程火车售票系统:两个指令,一个指令检查票是否卖完

  • Python网络编程使用select实现socket全双工异步通信功能示例

    本文实例讲述了Python网络编程使用select实现socket全双工异步通信功能.分享给大家供大家参考,具体如下: 在前面一篇<Python网络编程之TCP套接字简单用法>中,我们实现了tcp客户端与服务器的通信,但是功能十分局限,发送消息与接收消息不能同时进行. 接下来我将通过select这个模块,来实现全双工通信(随时可以接收信息以及发送信息),当然,用多线程也可以完成,这是后话. 那么,select为何物? select  -在单线程网络服务中器程序中,管理多个套接字连接 selec

  • python并发和异步编程实例

    关于并发.并行.同步阻塞.异步非阻塞.线程.进程.协程等这些概念,单纯通过文字恐怕很难有比较深刻的理解,本文就通过代码一步步实现这些并发和异步编程,并进行比较.解释器方面本文选择python3,毕竟python3才是python的未来,并且python3用原生的库实现协程已经非常方便了. 1.准备阶段 下面为所有测试代码所需要的包 #! python3 # coding:utf-8 import socket from concurrent import futures from selecto

  • Python 3中的yield from语法详解

    前言 最近在捣鼓Autobahn,它有给出个例子是基于asyncio 的,想着说放到pypy3上跑跑看竟然就--失败了. pip install asyncio直接报invalid syntax,粗看还以为2to3处理的时 候有问题--这不能怪我,好-多package都是用2写了然后转成3的--结果发 现asyncio本来就只支持3.3+的版本,才又回头看代码,赫然发现一句 yield from:yield我知道,但是yield from是神马? PEP-380 好吧这个标题是我google出来

  • 在Python中使用异步Socket编程性能测试

    OK,首先写一个python socket的server段,对开放三个端口:10000,10001,10002.krondo的例子中是每个server绑定一个端口,测试的时候需要分别开3个shell,分别运行.这太麻烦了,就分别用三个Thread来运行这些services. import optparse import os import socket import time from threading import Thread import StringIO txt = '''1111 2

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

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

  • Python异步编程之协程任务的调度操作实例分析

    本文实例讲述了Python异步编程之协程任务的调度操作.分享给大家供大家参考,具体如下: 我们知道协程是异步进行的,碰到IO阻塞型操作时需要调度其他任务,那么这个调度规则或者是算法是怎样的呢?现在有以下几个疑问: 1.多个任务准备好,需要运行时,优先执行哪一个? 2.一个任务运行时,如果别的任务准备好了,是否需要中断当前任务呢? 在网上找了很多资料,也无法找到相关的资料,于是编写了几个简单的程序,查看任务的执行过程. 根据Python的asyncio我们可以编写一个简单的程序: import a

  • Python socket模块ftp传输文件过程解析

    这篇文章主要介绍了Python socket模块ftp传输文件过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 使用环境:python3,window环境,需要在头部声明# -*- coding:utf-8 -*- 实现功能: 将sever端所处文件夹的文件,传输到client端所处的文件夹中. 并且通过md5检测是否出错. 客户端命令的形式是: get 文件名 client处的新文件是 文件名.new ftp_sever.py impo

  • Python使用微信接入图灵机器人过程解析

    这篇文章主要介绍了Python使用微信接入图灵机器人过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.wxpy库介绍 wxpy 在 itchat 的基础上,通过大量接口优化提升了模块的易用性,并进行丰富的功能扩展. 文档地址: https://wxpy.readthedocs.io 从 PYPI 官方源下载安装 pip install -U wxpy 2.图灵机器人 首先注册一个账号:http://www.turingapi.com/

  • python redis 批量设置过期key过程解析

    这篇文章主要介绍了python redis 批量设置过期key过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在使用 Redis.Codis 时,我们经常需要做一些批量操作,通过连接数据库批量对 key 进行操作: 关于未过期: 1.常有大批量的key未设置过期,导致内存一直暴增 2.rd需求 扫描出这些key,rd自己处理过期(一般dba不介入数据的修改) 3.dba 批量设置过期时间,(一般测试可以直接批量设置,线上谨慎操作) 通过

  • Python散点图与折线图绘制过程解析

    这篇文章主要介绍了Python散点图与折线图绘制过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在数据分析的过程中,经常需要将数据可视化,目前常使用的:散点图 折线图 需要import的外部包 一个是绘图 一个是字体导入 import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties 在数据处理前需要获取数据,从TXT XML csv

  • python Opencv计算图像相似度过程解析

    这篇文章主要介绍了python Opencv计算图像相似度过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.相关概念 一般我们人区分谁是谁,给物品分类,都是通过各种特征去辨别的,比如黑长直.大白腿.樱桃唇.瓜子脸.王麻子脸上有麻子,隔壁老王和儿子很像,但是儿子下巴涨了一颗痣和他妈一模一样,让你确定这是你儿子. 还有其他物品.什么桌子带腿.镜子反光能在里面倒影出东西,各种各样的特征,我们通过学习.归纳,自然而然能够很快识别分类出新物品.

  • python爬虫模拟浏览器访问-User-Agent过程解析

    这篇文章主要介绍了python爬虫模拟浏览器访问-User-Agent过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 模拟浏览器访问-User-Agent: import urllib2 #User-Agent 模拟浏览器访问 headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, li

  • python实现百度OCR图片识别过程解析

    这篇文章主要介绍了python实现百度OCR图片识别过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码如下 import base64 import requests class CodeDemo: def __init__(self,AK,SK,code_url,img_path): self.AK=AK self.SK=SK self.code_url=code_url self.img_path=img_path self.ac

  • Python自定义计算时间过滤器实现过程解析

    这篇文章主要介绍了Python自定义计算时间过滤器实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在写自定义的过滤器时,因为django.template.Library.filter()本身可以作为一个装饰器,所以可以使用: register = django.template.Library() @register.filter 代替 register.filter("过滤器名","函数名") 如果

随机推荐