生成器实现状态机解析器的核心是每个状态对应一个生成器函数,通过yield暂停、send()传递输入与控制权,避免显式状态变量和if/elif切换,提升逻辑清晰度与内存效率。

用生成器实现状态机解析器,核心在于让每个状态对应一个生成器函数,通过 yield 暂停执行、接收输入,并用 send() 在状态间传递控制权和数据。这种方式避免了显式的状态变量和大段 if/elif 切换,逻辑更清晰、内存更轻量。
状态即生成器:每个状态封装自己的行为
每个状态写成一个无限循环的生成器,内部用 yield 等待输入,根据输入内容决定是否跳转到下一个状态(通过返回新生成器或调用其 send())。
- 生成器首次需用
next()启动,走到第一个yield - 后续用
send(value)向当前状态传入数据,同时恢复执行 - 状态可返回另一个生成器(如
return next_state()),主循环据此切换
驱动循环:统一调度,解耦状态跳转
主解析循环不关心具体状态逻辑,只负责“唤醒当前状态 → 接收输入 → 获取下一个状态”:
- 初始化时启动首个状态生成器:
state = start_state(),然后next(state) - 对每条输入(如字符、token),调用
state.send(input) - 若状态返回新生成器(如
return error_state()),则更新state并再次next(state)启动它 - 若状态抛出
StopIteration,表示流程结束
示例:简易括号匹配状态机
识别字符串中是否括号成对出现(仅处理 ( 和 )):
def start_state():
count = 0
while True:
c = yield
if c == '(':
count += 1
yield
elif c == ')':
count -= 1
if count def parse(text):
state = start_state()
next(state) # 启动
for c in text:
try:
result = state.send(c)
if result == "unmatched_right":
return False
except StopIteration:
break
return count == 0 # 实际需把 count 提到外层或用类封装,此处为示意真实场景中建议将状态共享数据(如计数器、缓冲区)抽到类里,或用闭包保持,避免生成器间无法通信的问题。
优势与注意点
- ✅ 状态逻辑隔离:每个生成器只专注自身转移条件
- ✅ 协程式流控:无需递归或栈模拟,天然支持暂停/恢复
- ⚠️ 不适合复杂状态共享:多个状态需共用变量时,推荐用类封装状态机,生成器仅作协程接口
- ⚠️ 调试稍难:状态切换隐含在
send和return中,建议加日志或状态名标识











