yield from 生成器 协程

本文详细探讨了Python中的yield from关键字及其在生成器和协程中的作用。通过示例,解释了yield from如何启动和停止,以及如何在生成器之间传递控制权和数据。它被比喻为全双工管道,允许调用方与子生成器之间进行数据交互,直至子生成器抛出StopIteration异常,此时yield from捕获并重新抛出该异常,终止生成器的执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先,先理解一个概念, 把yield 当作是一种流程控制工具.

1 . yield 将在产出值后 停止. 例如: yield 1 . 当 1 产出后,此生成器将停止运行,将控制权交给调用者.

      yield 同时可以获取值, 如果调用方 send();

2. yield from 如果在函数中, 则此函数也是一个生成器,  与 yield 一样, 终止是也会抛出StopIteration

     yield from 何时启动 ,运行至哪?  

     由下面第4个例子可知  .yieldfrom 是一个生成器,所以 next() 即启动, 运行到yield from 后面的子生成器中的yield 暂停;

     yield from 何时停止 ?

     由下面第4个例子可知 . 当子生成器抛出StopIteration时, yield from 将获取返回值 . 并由于 yield from 自身是一个生成器.

      所以再次抛出StopIteration;

3. yield from 实现代码: yield from 实现

#自己实现一个 itertools.chain 函数
def iter_func(*args):
    for it in args:
        for item in it:  
            yield item

g = iter_func('abc','123') #2个可迭代对象(str)
print(list(g))

#输出:['a', 'b', 'c', '1', '2', '3']

 

使用 yield from 修改一下 , 可以看到 yield from 可以代替 for . 用于迭代

def iter_func2(*args):
    for it in args:
        yield from it

g = iter_func2('abc','123')
print(list(g))
#输出 :['a', 'b', 'c', '1', '2', '3']
#与上个例子是一样的.

 

 

获取协程返回的值 , 返回的值在异常中:

#让协程返回一个值
Result = namedtuple('Result', "count avg")
def avg():
    total = 0
    count = 0
    average = 0
    while True:
        print('enter avg while block')
        recv = yield average
        print('after yield , recvied: ' , recv)
        if recv == None:
            break
        total += recv
        count +=1
        average = total / count
    return Result(count,average)


a = avg()
next(a) #激活, 运行到yield 产出值后停止
a.send(10)
a.send(30)
try:
    a.send(None)
except StopIteration as ex:
    print("获取结果: " , ex.value)

 

 

yield from 将捕获异常, 并获取返回的值 , 修改上面捕获异常的代码 , avg函数不变 . 注意yield from 只能写在函数内:

    如果有unix - c 编程基础的可以看一下  :

    yield from 相当于是一个 socketpair / pipe的全双工管道 , 父进程(调用方)  写入数据( send ), 子进程( yield 子生成器) 从管道中读       取数据( yield 获取数据),

    最终,子进程把数据写入管道由父进程获取 ( yield from 返回值)

 

在这个例子中, 暂且称avg 是一个子生成器  ,由 yield from 调用;

from inspect import getgeneratorstate

def yield_from_func():
    '''
      将控制权移交到 avg 中. 而avg 中的yield 后,将控制权移交给调用方,即__main__.
      请注意 yield from 跟 yield 一样, 都不是阻塞性的
      yield from 就像电话线一样, 能让调用方 与 avg() 子生成器 进行通话
    '''
    ret = yield from avg() 
    print("ret : " , ret)   # 这行代码将在 avg() 抛出异常后运行


a = yield_from_func()
print("yield from func 是一个函数:",yield_from_func)
print("a 是一个生成器 :",a)
print("type(a) :" , type(a))

next(a) #激活 , 将运行到 avg 中的 yield
ret = a.send(10)  # 传递给avg 中的yield , yield  获取 10 , yield from 就像一个管道一样
print("result from yield :", ret) #  由 avg 中的yield 产出
print(getgeneratorstate(a)) #获取生成器状态
a.send(None)    # avg 中断, yield from 捕获异常, 获取返回值. 至此, yield from 结束返回

 

上面的代码将抛出 StopIteration , 此异常是 yield from 抛出的, 因为yield from 的函数也是一个生成器, 一旦结束就抛StopIteration

yield from 就跟管道一样, 能让调用方与一个子生成器相互传递数据 , 一个send , 一个 yield . 

yield from 作为中间组件存在,转移控制权给子生成器, 直到子生成器抛出异常, yield from 将捕获异常,

同时恢复运行.

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值