异常处理

基本语法

try:
    result = 10 / 0
except ZeroDivisionError:
    print("除零错误")
except (TypeError, ValueError) as e:
    print(f"类型或值错误:{e}")
except Exception as e:
    print(f"其他异常:{e}")
else:
    print(f"结果:{result}")   # 无异常时执行
finally:
    print("完成")              # 无论如何都执行

异常层次结构

BaseException
├── SystemExit          # sys.exit()
├── KeyboardInterrupt   # Ctrl+C
└── Exception
    ├── ArithmeticError
    │   └── ZeroDivisionError
    ├── LookupError
    │   ├── IndexError
    │   └── KeyError
    ├── TypeError
    ├── ValueError
    ├── AttributeError
    ├── NameError
    ├── OSError
    │   └── FileNotFoundError
    ├── RuntimeError
    │   └── RecursionError
    ├── StopIteration
    └── ImportError
        └── ModuleNotFoundError

raise

def divide(a, b):
    if b == 0:
        raise ValueError("除数不能为零")
    return a / b
 
# 重新抛出当前异常
try:
    divide(1, 0)
except ValueError:
    print("已记录日志")
    raise                        # 原样重新抛出
 
# 异常链(保留原始上下文)
try:
    int("abc")
except ValueError as e:
    raise RuntimeError("转换失败") from e

自定义异常

class AppError(Exception):
    """应用基础异常"""
 
class DatabaseError(AppError):
    def __init__(self, message: str, query: str = ""):
        super().__init__(message)
        self.query = query
 
    def __str__(self):
        return f"{super().__str__()} | query: {self.query}"
 
class NotFoundError(DatabaseError):
    pass
 
try:
    raise NotFoundError("记录不存在", "SELECT * FROM users WHERE id=99")
except DatabaseError as e:
    print(e)   # 捕获所有 DatabaseError 子类

上下文管理器与异常

# with 确保资源释放
with open("file.txt") as f:
    data = f.read()   # 异常时也会自动关闭
 
# 自定义上下文管理器
from contextlib import contextmanager
 
@contextmanager
def managed_resource():
    print("获取资源")
    try:
        yield "resource"
    except Exception as e:
        print(f"处理异常:{e}")
        raise
    finally:
        print("释放资源")
 
with managed_resource() as res:
    print(res)

常用模式

# 安全访问字典
val = d.get("key")               # 不存在返回 None
 
# 安全类型转换
try:
    n = int(user_input)
except ValueError:
    n = 0
 
# 忽略特定异常
from contextlib import suppress
with suppress(FileNotFoundError):
    os.remove("temp.txt")
 
# 记录完整堆栈
import logging
try:
    risky_operation()
except Exception:
    logging.exception("操作失败")  # 自动包含 traceback

最佳实践

# ❌ 捕获过宽,吞掉所有异常
try:
    do_something()
except Exception:
    pass
 
# ✅ 只捕获预期的异常
try:
    do_something()
except (ValueError, TypeError) as e:
    handle_error(e)
 
# ❌ 用异常做流程控制(性能差)
try:
    val = my_dict["key"]
except KeyError:
    val = "default"
 
# ✅ 用内置方法
val = my_dict.get("key", "default")

相关链接