核心要点

  • 掌握 try/except/else/finally 语义与执行顺序

  • 能区分 Exception 层级并避免裸 except

  • 知道 raise、自定义异常、with 与上下文管理器

标准回答

基本结构

python
try:
    risky()
except ValueError as e:
    handle(e)
except (TypeError, KeyError):
    handle_multi()
else:
    on_success()
finally:
    cleanup()  # 必定执行

最佳实践

  • 捕获具体异常,避免裸 except: 吞掉 KeyboardInterrupt
  • raise ... from e 保留异常链
  • 自定义异常继承 Exception,不要继承 BaseException(除系统级)
  • 文件/锁/连接用 with open(...) as f: 自动释放

工程场景:API 调用重试、数据管道脏数据跳过、训练中断保存 checkpoint

常见误区

⚠️ 常见踩坑

裸 except: 或 except Exception 吞掉所有异常(连 KeyboardInterrupt、拼写错误导致的 NameError 也被静默),排障困难——应捕获具体类型。另一个坑:在 except 里用 raise NewError() 而非 raise NewError() from e,会丢失原始堆栈/异常链,看不到根因。

追问

追问 1else 和 finally 分别在什么时候执行?

elsetry 未抛异常时执行,常用于「成功路径」的收尾;finally 无论是否异常都会执行(除非进程被 kill),常用于释放资源。returntry 中也会先执行 finally 再真正返回。

追问 2Exception 和 BaseException 有什么区别?

BaseException 是所有异常的根;Exception 是其子类,也是绝大多数业务异常的基类。KeyboardInterruptSystemExitGeneratorExit 直接继承 BaseException 而非 Exception,故 except Exception 不会捕获它们——这正是让 Ctrl+C 能中断程序的原因。自定义异常应继承 Exception。

追问 3如何用上下文管理器处理异常?

with 块会在退出(含异常)时调用对象的 __exit__(exc_type, exc_val, tb),可在此释放资源;__exit__ 返回 True 表示「已处理、吞掉异常」,返回 False/None 则异常继续向上抛。常用 contextlib.suppress(FileNotFoundError) 优雅忽略特定异常,或 @contextmanager 装饰生成器自定义 setup/teardown。

延伸学习

与本题相关的知识库文章、术语、工具与行业资讯。