Python中yield和yield from的用法

原文链接: https://www.cnblogs.com/cnkai/p/7514828.html

调用方 委托生成器

yield from 直接给出循环后的结果
yield from 委托者和子生成器直接通信
yield from 直接处理stopIteration错误 并把结果返回
jieshou=yield chuanchu
左边是接收值 右边是传入值 既是生产者也是消费者

调用方 main 委托方 子生成器(位于委托方内部)
yield 同时接受值传递给等号左边的变量,同时返回其后面的变量给外面的函数

yield from 总结
看完代码,我们总结一下关键点:

  1. 子生成器生产的值,都是直接传给调用方的;调用方通过.send()发送的值都是直接传递给子生成器的;如果发送的是 None,会调用子生成器的__next__()方法,如果不是 None,会调用子生成器的.send()方法;
  2. 子生成器退出的时候,最后的return EXPR,会触发一个StopIteration(EXPR)异常;
  3. yield from表达式的值,是子生成器终止时,传递给StopIteration异常的第一个参数;
  4. 如果调用的时候出现StopIteration异常,委托生成器会恢复运行,同时其他的异常会向上 “冒泡”;
  5. 传入委托生成器的异常里,除了GeneratorExit之外,其他的所有异常全部传递给子生成器的.throw()方法;如果调用.throw()的时候出现了StopIteration异常,那么就恢复委托生成器的运行,其他的异常全部向上 “冒泡”;
  6. 如果在委托生成器上调用.close()或传入GeneratorExit异常,会调用子生成器的.close()方法,没有的话就不调用。如果在调用.close()的时候抛出了异常,那么就向上 “冒泡”,否则的话委托生成器会抛出GeneratorExit异常。

协程:子生成器报错会直接把错误返回给调用方
和函数调用差不多 和同步编码方式一样

协程里面耗时的操作 比如 IO,time.sleep 等不能单独成行
卸载内部 只能放在yield 或者 yield from 后面

def fun_inner():
i = 0
while True:
i = yield i #传什么就返回什么

def fun_outer():
a = 0
b = 1
inner = fun_inner()
inner.send(None)
while True:
a = inner.send(b)
b = yield a #b原来不管是什么值 都会变成传入的值,传出的值为a

if name == ‘main’:
outer = fun_outer()
outer.send(None)
for i in range(5):
print(outer.send(i))

下面是yield from的实现方式:

def fun_inner():
i = 0
while True:
i = yield i

def fun_outer():
yield from fun_inner() #直接返回另一个生成器产生的值
直接调用另一个生成器

if name == ‘main’:
outer = fun_outer()
outer.send(None)
for i in range(5):
print(outer.send(i))

Python中yield和yield from的用法

        
        

yield

python中yield的用法很像return,都是提供一个返回值,但是yield和return的最大区别在于,return一旦返回,则代码段执行结束,但是yield在返回值以后,会交出CUP的使用权,代码段并没有直接结束,而是在此处中断,当调用send()或者next()方法之后,yield可以从之前中断的地方继续执行。

在一个函数中,使用yield关键字,则当前的函数会变成生成器。

下面生成一个斐波那契数列。

def fib(n):
    index = 0
    a = 0
    b = 1
while index < n:
    yield b
    a,b = b, a+b
    index += 1
  1. 生成器对象
fib = fib(100)
print(fib)


打印出来的结果是一个生成器对象,并没有直接把我们想要的值打印出来。

  1. next()方法
fib = fib(100)
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))

它的执行顺序是这样的,每次yield返回之后,程序将会中断,当出现next(fib)之后,程序将会从之前中断的地方继续执行。 python新版本中,不再提供fib.next()方法。

  1. send()方法

使用send()方法允许我们向生成器中传值。

import time

def fib(n):
index = 0
a = 0
b = 1

while index < n:
    sleep = yield b
    print('等待%s秒' %sleep)
    time.sleep(sleep)
    a,b = b, a+b
    index += 1

fib = fib(20)
print(fib.send(None)) # 效果等同于print(next(fib))
print(fib.send(2))
print(fib.send(2))
print(fib.send(2))
print(fib.send(2))

Python中yield和yield from的用法_第1张图片

执行顺序如下:
首先,创建生成器对象
调用fib.send(None)方法,此处作用与next(fib)相同,程序返回当前b的值1, 程序中断。
调用fib.send(2)方法,程序被唤醒,将2传递给yield之前的变量sleep,程序继续运行,直到遇到yield将新的b返回,程序再次中断。
如此继续下去,直到程序结束。

yield from

前面的都是单一层次的生成器,并没有嵌套,如果是多个生成器嵌套会怎么样呢,下面是一个例子。

def fun_inner():
    i = 0
    while True:
        i = yield i

def fun_outer():
a = 0
b = 1
inner = fun_inner()
inner.send(None)
while True:
a = inner.send(b)
b = yield a

if name == main:
outer = fun_outer()
outer.send(None)
for i in range(5):
print(outer.send(i))

在两层嵌套的情况下,值的传递方式是,先把值传递给外层生成器,外层生成器再将值传递给外层生成器,内层生成器在将值反向传递给外层生成器,最终yield出结果。如果嵌套的层次更多,传递将会越麻烦。

下面是yield from的实现方式:

def fun_inner():
    i = 0
    while True:
        i = yield i

def fun_outer():
yield from fun_inner()

if name == main:
outer = fun_outer()
outer.send(None)
for i in range(5):
print(outer.send(i))

效果是一样的,但是明显的代码量减少了,嵌套传值的时候,并不需要我们手动实现。

分类: Python
好文要顶 关注我 收藏该文
cnkai
关注 - 0
粉丝 - 85
+加关注
0
0
« 上一篇: Python多进程
» 下一篇: Selenium快速入门(上)
posted @ 2017-09-13 14:36  cnkai 阅读( 1480) 评论( 0) 编辑 收藏
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191018154227110.jpg)

你可能感兴趣的:(Python中yield和yield from的用法)