6月2日 01:35

Python 异常处理怎么写?try/except/else/finally 和自定义异常详解

Python 用 try/except 捕获异常,else 放无异常时执行的代码,finally 放无论如何都执行的清理逻辑。自定义异常继承 Exception,让错误类型可区分。

基本结构

python
try: 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

shell
BaseException +-- SystemExit # sys.exit() +-- KeyboardInterrupt # Ctrl+C +-- Exception # 所有业务异常的基类 +-- ValueError +-- TypeError +-- KeyError +-- FileNotFoundError

不要捕获 BaseException——except:except BaseException: 会把 KeyboardInterruptSystemExit 也吞掉,程序无法正常退出。永远用 except Exception: 或更具体的异常类型。

自定义异常

python
class 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

捕获一个异常后抛出另一个,保留原始异常的堆栈:

python
try: data = json.loads(raw) except json.JSONDecodeError as e: raise DataFormatError("数据格式错误") from e

from e 让新异常的 __cause__ 指向原始异常。调试时能看到完整的异常链。不加 from e,原始异常的堆栈信息会丢失。

常见反模式

1. 空 except 吞掉所有错误

python
try: do_something() except: # 错误!吞掉 KeyboardInterrupt pass # 正确做法 except Exception as e: log.error(f"操作失败: {e}")

2. except 块太宽

python
try: 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。

python
def foo(): try: return 1 finally: return 2 # 覆盖 try 里的 print(foo()) # 2
标签:Python