yield
带有 yield 的函数不再是一个普通函数,而是一个生成器generator
把生成器当作管道

def add_A(seq):for item in seq:yield item + '-A'def add_B(seq):for item in seq:yield item + '-B'def add_C(seq):for item in seq:yield item + '-C'seq = ['apple', 'banana', 'orange']stacked_generator = add_C(add_B(add_A(seq)))for item in stacked_generator:print(item)

yield 可以接受传值

def receiver():while True:received_item = yieldprint('收到:', received_item)def caller():recv = receiver()next(recv) # 使生成器前进到 yieldfor i in 'abcd':recv.send(i)caller()

那 send 函数的返回值是什么呢?

def receiver():call_times = 0while True:item = yield call_timesprint('收到:', item)call_times += 1def caller():recv = receiver()next(recv)for i in 'abcd':ret_value = recv.send(i)print('返回值: ', ret_value)caller()

给生成器传值
可以通过调用生成器的 send 方法来向生成器传值,这将让生成器从上次暂停的 yield 前进到下个 yield,并将产出值作为 send 的返回值。当我们没有使用send方法时generator只能产出而不能消费,当我们使用了send后generator便可以进行消费了

def generator():item = yield 'a'#先将'a'返回给调用方,让后将send的值让generator进行消费print(item)another_item = yield 'b'gen = generator()
print(next(gen))
print(gen.send(1))

关闭一个生成器
通过调用生成器 close 方法可以生成器在 yield 语句处抛出 GeneratorExit。这时仅允许 return,如果没有捕捉这个错误,生成器会静默关闭,不抛出错误。

def generator():times = 0while True:yield timestimes += 1gen = generator()
print(next(gen))
print(next(gen))
gen.close() # 不会抛出错误

抛出错误

def generator():try:yield 'apple'except RuntimeError as e:print('捕捉到:', e)yield 'banana'gen = generator()
print(next(gen))
print(gen.throw(RuntimeError, '运行错误'))

生成器返回值
如果在生成器函数中加上 return 那在运行到 return 时将会把返回值作为 StopIteration 的值传递出去。这个是 Python3 的特性,Python2 生成器不能返回某个值。

def generator():yieldreturn 'apple'g = generator()
next(g)
try:next(g)
except StopIteration as e:print(e)

yield from
Python3.3版本的PEP 380中添加了yield from语法,生成器委托
使用 yield from 可以帮你对一个生成器不断调用 next 函数,并返回生成器的返回值。言下之意是你可以在生成器里调用生成器。
我们可以用yeild from来简单的实现chain这个模块:
yield from iterable,from后面是一个iterable对象

def my_chain(*args, **kwargs):for my_iterable in args:yield from my_iterable# for value in my_iterable:#     yield valuefor value in my_chain([12, 21, 11, 10, 23, 12], 'liyuanchao'):print(value)

三个概念理清楚

def gens():yield 'test'def g1(gen):yield from gendef test():g = g1(gens())g.send(None)

1. test为调用方,g1为委托生成器,gen为子生成器
2. yield from会在调用方和子生成器之间建立一个双向通道,这里的gen直接和test建立双向通道,也就是说子生成器gen yield出来的值是直接交给test的,并且这里的send的值是直接发送给子生成器的。

yield from的两个高级的用法的例子
例1.Bobby牌商品的统计

final_result = {}def sales_sum(pro_name):total, nums = 0, []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 = {"bobby牌面膜": [1200, 1500, 3000],"bobby牌手机": [28, 55, 98, 108],"bobby牌大衣服": [280, 560, 778, 70]}for key, data_set in data_sets.items():print('start key:', key)m = middle(key)m.send(None)for value in data_set:m.send(value)m.send(None)print("final_result:", final_result)

例2.体重统计

from collections import namedtuple
Result = namedtuple('Result', 'count average')
# the subgenerator
def averager():total = 0.0count = 0average = Nonewhile True:term = yieldif term is None:breaktotal += termcount += 1average = total / countreturn Result(count, average)
# the delegating generator
def grouper(results, key):while True:#只有当生成器averager()结束,才会返回结果给results赋值results[key] = yield from averager()
def main(data):results = {}for key, values in data.items():group = grouper(results, key)next(group)for value in values:group.send(value)group.send(None)report(results)
#如果不使用yield from,仅仅通过yield实现相同的效果,如下:
def main2(data):for key, values in data.items():aver = averager()next(aver)for value in values:aver.send(value)try: #通过异常接受返回的数据aver.send(None)except Exception as e:result = e.valueprint(result)
def report(results):for key, result in sorted(results.items()):group, unit = key.split(';')print('{:2} {:5} averaging {:.2f}{}'.format(result.count, group, result.average, unit))
data = {'girls;kg':[40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5],'girls;m':[1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43],'boys;kg':[39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],'boys;m':[1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46],
}
if __name__ == '__main__':main(data)

总结
gen = generator()

  • 使一个生成器前进 next(gen)

  • 传递一个值 gen.send(item)

  • 中止生成器 gen.close()

  • 抛出错误 gen.throw(exc, val, tb)

  • 委托 result = yield from gen

1.迭代器(即可指子生成器)产生的值直接返还给调用者
2.任何使用send()方法发给委派生产器(即外部生产器)的值被直接传递给迭代器。如果send值是None,则调用迭代器next()方法;如果不为None,则调用迭代器的send()方法。如果对迭代器的调用产生StopIteration异常,委派生产器恢复继续执行yield from后面的语句;若迭代器产生其他任何异常,则都传递给委派生产器。
3.除了GeneratorExit 异常外的其他抛给委派生产器的异常,将会被传递到迭代器的throw()方法。如果迭代器throw()调用产生了StopIteration异常,委派生产器恢复并继续执行,其他异常则传递给委派生产器。
4.如果GeneratorExit异常被抛给委派生产器,或者委派生产器的close()方法被调用,如果迭代器有close()的话也将被调用。如果close()调用产生异常,异常将传递给委派生产器。否则,委派生产器将抛出GeneratorExit 异常。
5.当迭代器结束并抛出异常时,yield from表达式的值是其StopIteration 异常中的第一个参数。
6.一个生成器中的return expr语句将会从生成器退出并抛出 StopIteration(expr)异常。
参考:
Python异步编程详解
生成器进化到协程
Python Async/Await入门指南

从yield到yield from相关推荐

  1. Python中yield和yield from的用法

    yield 后面接的是 future 对象 调用方 委托生成器 yield from 直接给出循环后的结果 yield from 委托者和子生成器直接通信 yield from 直接处理stopIte ...

  2. python yield from yield_python yield和yield from用法总结详解 python yield和yield from用法总结...

    #!/usr/bin/env python # -*- coding: utf-8 -*-from inspect import isgeneratorfunction def fab(max): n ...

  3. python yield from_简述 yield 和 yield from

    yield 函数可以看成是一堆指令的集合.在函数中加入yield可以把一个函数变成一个generator,虽然调用的方式不一样了,但是其实现的功能和原来的函数基本是一样的. 而yield在这其中的作用 ...

  4. python协程--yield和yield from

    字典为动词"to yield"给出了两个释义:产出和让步.对于 Python 生成器中的 yield 来说,这两个含义都成立.yield item 这行代码会产出一个值,提供给 n ...

  5. 从yield 到yield from再到python协程

    yield 关键字 def fib():a, b = 0, 1while 1:yield ba, b = b, a+b yield 是在:PEP 255 -- Simple Generators 这个 ...

  6. yield 和 yield*

    yield yield 关键字用来暂停和恢复一个生成器函数(function*) 举例: function* gen(index) {while (index < 2) {yield index ...

  7. yield 跟 yield * 的区别

    yield表达式的值,是下一个iter.next的参数值 yield*表达式的值,是yield*后的iterable在done为true时的value值. yield * 的使用: function* ...

  8. js中的yield、yield*和Generator函数

    基本概念 yield和yield*都是js中的关键字,他们不能直接使用:只能配合Generator进行使用:Generator是一种函数,声明方式和普通函数类似,只不过要在function后面加个*( ...

  9. python进阶:yield与yield from

    目录 yield与生成器 send close throw yield from yield与生成器 前面我们介绍过生成器:迭代器.可迭代对象.生成器的区别和联系 使用了 yield 的函数被称为生成 ...

最新文章

  1. 这7款实用windows软件,太让人惊喜了!
  2. 比较两个字符串是否相等
  3. mysql 5.7报1055错误的解决方法
  4. iptable 命令
  5. currenthashmap扩容原理_ConcurrentHashMap实现原理和源码解读
  6. P1038 神经网络(拓扑排序)
  7. java 日期 区间_如何实现时间区间的分割??
  8. 面具公园登陆不了未能找到服务器,面具公园之后,伴圈app成为了新的替代
  9. 北京市交管局联合高德地图发布北京中考出行提示
  10. hibernate使用二级缓存ehcahe的配置
  11. android开发环境的调研
  12. day02:关于惯性导航工具箱的学习与使用:use of the progen
  13. latex 字体加粗失效
  14. PPDuck3 for Mac(pp鸭图片批量压缩工具)最新官方版免下载
  15. 华为h12m03装系统_华为H22H-03服务器怎么从U盘装系统?
  16. 怎么用数学绘图软件验证扇形面积公式?
  17. 终于明白为什么人人都爱Django了,Django果然天下第一
  18. C语言程序设计第六次作业——循环结构(2)
  19. ARK方舟的自我拯救之路 - 驴妈妈DevOps实践
  20. Python opencv PIL numpy base64互相转化

热门文章

  1. 2020 年 7 月编程语言排行榜
  2. 区块链亲民应用场景大猜想 第一次或将献给超大文件传输
  3. 中英文翻译功能 php,PHP微信开发之翻译功能
  4. oracle11g memory_target,oracle11g要求在操作系统层设定共享内存/dev/shm,且大于MEMORY_TARGET...
  5. 淘宝小程序 表单组件checkbox的默认样式修改
  6. 【记录】easyexcel导出后打开文件报已损坏
  7. 美国计算机科学专业申请条件,美国CS计算机科学专业申请条件
  8. 使用图像扫描控件ScanOnWeb实现在线图像扫描
  9. Android原生webView概述
  10. 绿蓝色悖论(新归纳之谜)?