Files
Auto-Finance/.agents/docs/error-experience/2026-06-13-闭包内复用外层变量名导致UnboundLocalError.md

59 lines
2.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
last_reviewed: 2026-06-13
---
# 闭包内复用外层变量名导致 UnboundLocalError
## 错误现象
- 补充材料提交后,提取函数正常执行完成
- 日志停在 `travel_applications.json` 保存处,后续没有任何 Agent 处理日志
- 没有报错、没有异常堆栈,看起来像"停止"
- `result.json` 里实际记录了 `{"ok": false, "error": "local variable 'agent_session' referenced before assignment"}`
## 触发条件
- 在 Flask 路由中用 `threading.Thread` 启动后台任务
- 外层作用域已有一个变量(如 `agent_session`
- 闭包 `_run()` 内对同名变量既读又写:`agent_session = run_agent_round(session_dir, agent_session, ...)`
## 原因
Python 变量作用域规则:**只要函数体内有任何对某标识符的赋值,该标识符在整个函数内都被视为局部变量**。
```python
agent_session = add_supplement(session_dir, agent_session, filenames) # 外层变量
def _run() -> None:
# ...
agent_session = run_agent_round( # 赋值 -> 整个 _run 内 agent_session 是局部变量
session_dir, agent_session, # 读局部变量,但此时还未赋值 -> UnboundLocalError
new_files=filenames,
)
```
`run_agent_round` 调用时,`agent_session` 作为参数被求值,但此时它还是未初始化的局部变量,触发 `UnboundLocalError`。该异常被 `except BaseException` 捕获后写入 result.json没有在日志中输出所以表现为"静默停止"。
## 修复方法
闭包内使用不同名称接收返回值:
```python
# 修复前
agent_session = run_agent_round(session_dir, agent_session, new_files=filenames)
# 修复后
new_session = run_agent_round(session_dir, agent_session, new_files=filenames)
```
后续对返回值的引用统一改为 `new_session`
## 防回归要点
| 场景 | 风险 | 检查方法 |
|------|------|----------|
| 在闭包/嵌套函数内赋值与外层同名的变量 | UnboundLocalError | ruff F823 规则 |
| `except BaseException` 吞掉异常且不打日志 | 静默失败,难以排查 | 至少记录 `log.exception` |
| 用 `# noqa: F823` 压制警告而不修复 | 问题持续存在 | noqa 只应用于确认安全的场景 |
**核心原则**:在闭包内需要接收外层变量的返回值时,始终使用不同的变量名。不要依赖 `nonlocal` 来修复合法性问题——换名字更简单、更安全。