优雅做法是每个yield数据源独立封装+外层统一协调+异常分类透传:各源函数精准捕获特定异常并raise from保留堆栈,外层仅处理协调级错误,else/finaly分离逻辑与清理,错误聚合分类返回并带来源标识。

单个内部 try-catch 块里塞多个条件分支去应对 yield 多数据源的复合报错,不是优雅做法——它容易混淆错误归属、掩盖真实失败点,还让调试和日志失去上下文。真正优雅的方式是:**每个 yield 数据源独立封装 + 外层统一协调 + 异常分类透传**。
每个数据源单独 try-except,不共用一个块
多个 yield 源(比如从 API、数据库、本地文件逐个产出数据)本质是并行或串行的独立操作。混在一个 try 里,一旦出错,你根本分不清是 requests 超时、SQL 执行失败,还是 JSON 解析出错。
- 为每个数据源写独立函数,内部用精准异常捕获(如
requests.Timeout、sqlite3.OperationalError、json.JSONDecodeError) - 在函数内用
raise from e保留原始堆栈,不吞掉底层细节 - 例如:
yield from fetch_from_api()和yield from load_from_csv()各自负责自己的异常边界
yield 迭代器外层加兜底,但只处理“协调级”错误
外层生成器本身不处理具体业务异常,只关注流程层面问题:
- 比如所有数据源都失败后抛出
NoDataAvailableError(自定义) - 捕获
GeneratorExit或提前中断时的清理逻辑(如关闭连接池) - 不在此处 catch
ValueError或ConnectionError——这些应由内层函数明确抛出并标记来源
用 else + finally 明确分离成功路径与收尾动作
在每个数据源函数中,避免在 except 里做副作用操作(比如记录日志时又触发新异常):
-
else块放正常 yield 逻辑,确保只在无异常时执行 -
finally放资源释放(如response.close()、cursor.close()),不依赖是否 yield 成功 - 这样既保证数据产出干净,又防止资源泄漏
错误聚合与分类返回,而非“统一吞掉”
面对多源 yield,用户常想“只要有一个成功就行”,但报错不能模糊处理:
- 收集各源的异常(如用
list[Exception]),最后按类型归类:网络类、解析类、权限类 - 提供
yield_result_or_raise()这样的辅助函数,允许调用方选择“跳过失败源”或“任一失败即中断” - 日志中带上来源标识(
"api_v2: Timeout"、"csv_user: Empty file"),而不是笼统写“yield 出错”

















