控制反转(IoC)是将流程控制权从函数内部移交至外部调用者,生成器通过yield暂停执行、由外部next()/send()驱动,天然实现该思想:函数仅定义可插拔的暂停点,分支逻辑与执行节奏均由外部决定。

生成器可以天然实现控制反转(IoC),因为它的执行权不在函数内部,而在外部调用者手中——每次 next() 都由外部触发,yield 则把控制权交出去,等待下一次指令。这和传统函数“自己决定流程、一路执行到底”的模式截然不同。
用 yield 暂停并暴露决策点
在函数中用 yield 标记出“可插拔”的暂停位置,每个 yield 相当于一个钩子:函数在此停下,把当前状态和选择权交给外部;外部通过 send() 或下次 next() 决定接下来走哪条路。
- 比如一个表单校验生成器,在每项验证后
yield result,外部收到结果后决定是继续下一项、重试当前项,还是直接终止 - yield 不仅能传出数据,还能接收外部输入(配合
send(value)),让外部直接注入下一步参数或指令
用 send() 实现动态行为切换
生成器启动后,首次用 next(g) 启动到第一个 yield;之后改用 g.send(cmd),就能把命令传进函数内部,让它根据 cmd 改变后续逻辑。
- 例如一个状态机生成器:
yield 'ready'后暂停,外部调用g.send('start'),函数内部就进入运行态;再send('pause')就切到暂停态 - 注意:第一次不能用 send(除非先 next 启动),且 yield 表达式左侧要写成
cmd = yield value才能接住传入值
用外部循环接管整个执行流
真正的控制反转体现在:**谁调用 next / send、何时调用、传什么,完全由外部逻辑决定**——生成器只提供能力接口,不主导节奏。
- 你可以用 while 循环 + 条件判断来驱动生成器,比如按用户按键、网络响应、定时器触发来决定是否推进
- 也可以把生成器包装成协程,由事件循环统一调度,实现异步 I/O 中的分步控制(如 asyncio 中的 async/await 底层就基于生成器)
- 关键不是“能不能做”,而是“不主动执行”——生成器函数体里没有 if-else 跳转逻辑,跳转由外部输入驱动
对比传统函数,突出 IoC 本质
普通函数像“独白”:写死流程,调用即执行完毕;生成器像“对话脚本”:只写台词和停顿点,谁说下一句、什么时候说、说哪句,全由对方(外部)定。
- 传统方式:函数内用 if/while 控制分支 → 控制权在内
- 生成器方式:函数只 yield 状态或问题,外部根据 yield 值决定 send 什么 → 控制权在外
- 这种解耦让业务逻辑(外部策略)和步骤定义(生成器)可以独立变化,符合依赖倒置原则

















