要使 generator 的 .throw() 生效,必须将 yield 语句置于 try 块中并配对匹配类型的 except;否则异常直接终止迭代。拦截后可 yield 新值、return 结束或 re-raise,finally 确保资源清理且不可含 yield。

要让迭代器的 .throw() 方法在 Generator 内部真正起作用,关键不是“调用 throw”,而是**提前在 yield 暂停点周围布防**——把 yield 放进 try 块里,否则异常直接冒泡终止,根本没机会拦截。
必须把 yield 包裹在 try-except 中
Generator 不会自动捕获 .throw() 注入的异常,它只是把异常“扔”到当前 yield 所在位置,等效于在那一行执行 raise exc。所以拦截的前提是:yield 语句本身得处于一个可捕获该异常的上下文中。
- 正确写法:yield 出现在 try 块内,且 except 子句能匹配 throw 的异常类型
- 错误写法:yield 独立在外,或被包裹在不匹配的 except 中(比如 throw ValueError 却只 catch TypeError)
- 注意:except 后可选择继续 yield 新值、return 提前结束,或重新 raise —— 这决定了状态机后续是否还能推进
throw 的参数要和 except 类型严格对应
gen.throw(TypeError, "bad input") 只有在生成器内部有 except TypeError: 才会被捕获;如果只写了 except Exception:,也能接住,但不够精准。建议按业务意图明确声明异常类型。
- type 参数必填,通常是异常类(如
ValueError),不是字符串 - value 参数可选,作为异常实例的构造参数,比如
gen.throw(ValueError, "invalid format") - traceback 参数极少手动传,一般由解释器自动填充
拦截后的行为决定状态机走向
catch 到异常后怎么做,直接影响 Generator 是继续运行、跳过一项,还是彻底退出:
- 想跳过当前项并继续:在 except 中执行新的
yield(例如 yield None 或默认值) - 想终止迭代:直接
return,此时 .throw() 调用会返回 yield 表达式的值(如果有) - 想转换异常再抛出:用
raise KeyError("key missing") from None替换原异常,避免堆栈污染 - 想恢复原状重试:不推荐在 except 里再次
yield原值,容易引发逻辑混乱;更适合用 send() 重新输入
配合 finally 做资源兜底,避免状态残留
即使 throw 触发了异常,只要还没退出函数体,finally 仍会执行。这对释放文件、连接、锁等资源至关重要:
- 所有外部资源操作(open、connect、acquire)应放在 try 前或 try 内
- 清理逻辑(close、release、disconnect)统一写在 finally 块中
- 切记:finally 里不能出现 yield,否则会触发 RuntimeError











