Python异常处理的核心在于理解异常对象生成、栈帧传播及try/except/finally协作机制,而非单纯记忆语法。
这标题看着像课程宣传,实际想解决的无非是:Python异常到底怎么捕获才不漏、怎么抛才合理、为什么有时 except 像没生效一样?答案不在“学第几讲”,而在搞清三件事:异常对象怎么生成、栈帧怎么传播、try/except/finally 怎么协作。
很多人以为 raise ValueError("xxx") 就是“抛个错误”,其实它创建了一个 ValueError 实例,并立刻中断当前执行流。这个对象有 args、__traceback__、__cause__ 等属性,能被检查、修改、链式传递。
sys.exc_info() 可拿到当前异常三元组:(type, value, traceback),比只写 except: 更可控raise ... from ... 显式构造异常链,避免丢失原始上下文;raise 单独写会原样重抛(保留原 traceback)Exception 或其子类,否则 except Exception: 捕不到(比如直接继承 BaseException 的会跳过常规捕获)写 except ValueError: 能捕获所有 ValueError 及其子类(如 UnicodeDecodeError),但不会捕获 TypeError——哪怕错误信息里有“value”这个词。
except 按顺序匹配,**先写的优先**;except Exception: 放最下面,否则会吞掉更具体的异常except (ValueError, TypeError): 是元组解包语法,不是“或”的逻辑短路;两个类型都按继承规则检查except: 等价于 except BaseException:,会捕获 KeyboardInterrupt 和 SystemExit,通常不该用finally 的作用是保证清
理代码在 try 块退出时运行(无论是否异常、是否 return、是否 break),但它依赖 Python 解释器正常接管控制权。
os._exit(0) 会立即终止进程,跳过所有 finally 和析构函数kill -9 强杀,finally 也失效finally 里又抛异常,它会覆盖 try 块里的异常(除非原异常还没被处理)try:
raise ValueError("original")
except ValueError:
print("handled")
raise KeyError("new") # 这个会取代 ValueError 被抛出
finally:
print("cleanup") # 仍会执行比如用 KeyError 判断字典键是否存在,或用 StopIteration 控制循环——这不是错,但性能差且语义不清。Python 提供了更直接的方式。
dict.get(key, default) 或 key in dict,比 try/except KeyError 快 2–3 倍(尤其键大概率存在时)for item in iterable:,别手动调 next() + 捕 StopIteration
try/except 主干流程真正难的不是记住语法,而是判断:这个异常该被谁处理?该继续向上冒泡,还是就地消化?该记录日志后重抛,还是转成用户友好的提示?这些决策藏在业务边界里,而不是 except 关键字后面。