6月2日 01:35
Python 异常处理怎么写?try/except/else/finally 和自定义异常详解
Python 用 try/except 捕获异常,else 放无异常时执行的代码,finally 放无论如何都执行的清理逻辑。自定义异常继承 Exception,让错误类型可区分。
基本结构
pythontry: result = 10 / 0 except ZeroDivisionError: print("除零错误") except (TypeError, ValueError) as e: print(f"类型或值错误: {e}") else: print("没有异常时执行") finally: print("无论如何都执行")
else在 try 块没有抛异常时执行,适合放"成功后才做的事"finally总是执行,即使 try 里有 return 或 except 里有 raise。用于释放资源(关闭文件、断开连接)
异常继承体系
所有异常继承自 BaseException,日常使用继承 Exception:
shellBaseException +-- SystemExit # sys.exit() +-- KeyboardInterrupt # Ctrl+C +-- Exception # 所有业务异常的基类 +-- ValueError +-- TypeError +-- KeyError +-- FileNotFoundError
不要捕获 BaseException——except: 或 except BaseException: 会把 KeyboardInterrupt 和 SystemExit 也吞掉,程序无法正常退出。永远用 except Exception: 或更具体的异常类型。
自定义异常
pythonclass BusinessError(Exception): """业务逻辑错误基类""" pass class InsufficientBalance(BusinessError): def __init__(self, balance, amount): self.balance = balance self.amount = amount super().__init__(f"余额不足: 余额 {balance}, 需要 {amount}") try: withdraw(account, amount) except InsufficientBalance as e: print(e) print(e.balance) # 100
自定义异常比直接 raise ValueError("余额不足") 好在:调用方可以按类型捕获(except InsufficientBalance),而不是解析错误消息字符串。
异常链:raise from
捕获一个异常后抛出另一个,保留原始异常的堆栈:
pythontry: data = json.loads(raw) except json.JSONDecodeError as e: raise DataFormatError("数据格式错误") from e
from e 让新异常的 __cause__ 指向原始异常。调试时能看到完整的异常链。不加 from e,原始异常的堆栈信息会丢失。
常见反模式
1. 空 except 吞掉所有错误
pythontry: do_something() except: # 错误!吞掉 KeyboardInterrupt pass # 正确做法 except Exception as e: log.error(f"操作失败: {e}")
2. except 块太宽
pythontry: value = data["key"] result = int(value) except Exception: # 太宽,KeyError 和 ValueError 混在一起 ... # 正确:分别处理 except KeyError: result = 0 except ValueError: result = -1
3. 用异常做流程控制
python# 错误:用异常判断 key 是否存在 try: value = d[key] except KeyError: value = default # 正确:用 get 或 in value = d.get(key, default)
异常比条件判断慢 10-100 倍。只对真正的"异常"情况用异常,正常流程用条件判断。
追问
finally 里的 return 会覆盖 try 里的 return 吗?
会。永远不要在 finally 里写 return。
pythondef foo(): try: return 1 finally: return 2 # 覆盖 try 里的 print(foo()) # 2