You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python 3.8中yield from触发StopIteration报错的原因咨询

生成器中send(None)抛出StopIteration的原因解析

问题描述

我是生成器的新手,我的理解是:当从生成器函数total_average中break时,会在wrap_average中隐式触发StopIteration,但wrap_average会向调用者返回None,程序不应出现StopIteration。但在Python 3.8中执行以下测试代码时,w.send(None)抛出了StopIteration错误,不清楚原因是什么?

测试代码:

def total_average():
    total = 0.0
    count = 0
    avg = None
    print("starting average generator")
    while True:
        num = yield avg
        if num is None:
            break
        total += num
        count += 1
        avg = total/count

def wrap_average(average_generator):
    """This is just a pipe to the generator"""
    print("starting wrap_average")
    avg = yield from average_generator

# Note: total_average() is the generator object. total_average is generator function
w = wrap_average(total_average())
# Execute everthing until hitting the first iterator. None being returned
print("starting the generator: ", next(w))
print(w.send(3))
print(w.send(4))
# Finish Coroutine
# ? Not sure why w.send(None) is giving me stop iteration?
w.send(None)

原因解析

当total_average中执行break时,生成器会直接终止,此时会抛出StopIteration异常。而wrap_average里的yield from语句会将子生成器(total_average)的终止信号直接向上传递——子生成器抛出的StopIteration不会被wrap_average捕获并转为返回值,而是会透传到外层的调用者,导致你看到的错误。

你可能误解了yield from的行为:avg = yield from average_generator确实会将子生成器终止时StopIteration的value属性赋值给avg(这里因为子生成器没有return,所以value是None),但这个赋值操作并不会阻止StopIteration异常向外层传播,外层调用者仍然会收到这个异常。

解决方法

如果不想让外层抛出StopIteration,可以通过两种方式处理:

方式一:在wrap_average中捕获StopIteration

修改wrap_average函数,显式捕获子生成器的终止异常:

def wrap_average(average_generator):
    """This is just a pipe to the generator"""
    print("starting wrap_average")
    try:
        avg = yield from average_generator
    except StopIteration:
        return avg

方式二:让total_average用return终止(更符合生成器规范)

将total_average中的break替换为return,返回当前计算的平均值,这样yield from会将这个返回值作为自己的返回值,同时不会向外传播StopIteration:

def total_average():
    total = 0.0
    count = 0
    avg = None
    print("starting average generator")
    while True:
        num = yield avg
        if num is None:
            return avg  # 用return替代break,返回最终平均值
        total += num
        count += 1
        avg = total/count

修改后再执行代码,w.send(None)就不会抛出StopIteration异常了。

内容的提问来源于stack exchange,提问作者Ruotong Jia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 09:06:38