如何让生成器支持 throw() 抛异常到生成器内部

技术百科 舞夢輝影 发布时间:2026-01-27 浏览:
只有含yield表达式(如received = yield value)的生成器才能用throw()触发except捕获;yield语句无法中断执行,throw()将直接终止生成器。

生成器必须用 yield 表达式而非 yield 语句

Python 中,只有函数体内包含 yield 表达式(即出现在等号右侧、能接收值的 yield),才能通过 throw() 向内部抛异常并被 except 捕获。如果只写 yield 语句(如 yield 42),它仍可迭代,但 throw() 只会终止生成器,无法进入 except 块。

常见错误现象:Generator.throw() 调用后直接抛出 StopIteration 或原异常未被捕获,本质是控制流没停在可中断的 yield 表达式上。

  • 正确写法:received = yield value —— 此处 yield 是表达式,暂停点可接收值或异常
  • 错误写法:yield value(无赋值)—— 控制流经过即继续,throw() 无法“插入”到执行中
  • 即使不打算接收值,也应写成 _ = yield valueyield value; continue 后补一个空 yield 表达式

throw() 必须在生成器暂停时调用

throw() 不是“发消息”,而是向当前暂停点注入异常。若生成器已结束(StopIteration 已 raise)、尚未启动(还没第一次 next()send(None)),或正在运行中(比如卡在某个循环里没遇到 yield),调用 throw() 都会报 RuntimeError: generator already executing 或直接失败。

使用场景:常用于协程式状态机,比如等待用户输入时,外部想强制中断并清理资源。

  • 首次启动必须用 next(gen)gen.send(None),否则 throw() 无效
  • 每次 throw() 后,生成器必须再次被驱动(next()send()),否则停留在抛异常后的暂停点
  • 若生成器在 try/finally 中,throw()

    触发异常时 finally 仍会执行

异常类型需与 except 匹配,且不能跳过 yield

生成器内 except 能捕获 throw() 的异常,前提是该 except 所在的 try 块覆盖了当前 yield 表达式所在的位置,并且异常类型一致。Python 不支持“跳转式捕获”——异常不会向上越过未激活的 try 块。

参数差异:gen.throw(TypeError, "msg") 等价于 gen.throw(TypeError("msg")),但推荐传入已实例化的异常对象,避免某些版本兼容问题。

  • yieldtry 外,throw() 会直接冒泡,不会进 except
  • except BaseException: 可捕获所有,但会吞掉 GeneratorExitSystemExit,慎用
  • 捕获后若不 returnyield,生成器立即结束;若继续 yield,则恢复迭代流程

实际例子:带错误恢复的计数生成器

下面是一个能响应 throw(ValueError) 并重置计数的生成器:

def counter():
    i = 0
    while True:
        try:
            i += 1
            # 必须是 yield 表达式,哪怕不接收值
            _ = yield i
        except ValueError:
            print("resetting...")
            i = 0

调用方式:

g = counter()
next(g) # → 1
next(g) # → 2
g.throw(ValueError) # 打印 resetting...,不抛异常
next(g) # → 1(已重置)

容易踩的坑:忘记在 throw() 后调用 next()send(),结果生成器停在 except 块末尾,下一次 next() 才真正产出值——这个延迟行为常被忽略。


# ai  # 是一个  # 出现在  # python  # 首次  # 跳转  # 迭代  # 还没  # 只会  # 不支持  # 循环  # 对象  # try  # throw  # 会报  # finally  # continue  # 停在  # raise 


相关栏目: <?muma $count = M('archives')->where(['typeid'=>$field['id']])->count(); ?> 【 AI推广<?muma echo $count; ?> 】 <?muma $count = M('archives')->where(['typeid'=>$field['id']])->count(); ?> 【 SEO优化<?muma echo $count; ?> 】 <?muma $count = M('archives')->where(['typeid'=>$field['id']])->count(); ?> 【 技术百科<?muma echo $count; ?> 】 <?muma $count = M('archives')->where(['typeid'=>$field['id']])->count(); ?> 【 谷歌推广<?muma echo $count; ?> 】 <?muma $count = M('archives')->where(['typeid'=>$field['id']])->count(); ?> 【 百度推广<?muma echo $count; ?> 】 <?muma $count = M('archives')->where(['typeid'=>$field['id']])->count(); ?> 【 网络营销<?muma echo $count; ?> 】 <?muma $count = M('archives')->where(['typeid'=>$field['id']])->count(); ?> 【 案例网站<?muma echo $count; ?> 】 <?muma $count = M('archives')->where(['typeid'=>$field['id']])->count(); ?> 【 精选文章<?muma echo $count; ?>

相关推荐

在线咨询

点击这里给我发消息QQ客服

在线咨询

免费通话

24h咨询:4006964355


如您有问题,可以咨询我们的24H咨询电话!

免费通话

微信扫一扫

微信联系
返回顶部