异常处理
Python 用异常(Exception)处理错误,遵循 EAFP(Easier to Ask Forgiveness than Permission)风格:先尝试,出错再处理。
基本语法
1 2 3 4 5 6 7 8 9 10
| try: result = 10 / 0 except ZeroDivisionError as e: print(f"除零错误: {e}") except (TypeError, ValueError) as e: print(f"类型或值错误: {e}") else: print("没有异常时执行") finally: print("无论是否异常都执行")
|
抛出异常
1 2 3 4 5 6
| def divide(a: float, b: float) -> float: if b == 0: raise ValueError("除数不能为零") return a / b
raise RuntimeError("something went wrong")
|
异常链
保留原始异常上下文:
1 2 3 4
| try: int("abc") except ValueError as e: raise RuntimeError("解析失败") from e
|
常见内置异常
| 异常 |
触发场景 |
ValueError |
值合法但语义不对 |
TypeError |
类型不匹配 |
KeyError |
dict 键不存在 |
IndexError |
序列索引越界 |
FileNotFoundError |
文件不存在 |
AttributeError |
对象无该属性 |
StopIteration |
迭代器结束 |
自定义异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class AppError(Exception): """应用基础异常。"""
class NotFoundError(AppError): def __init__(self, resource: str, id: int): self.resource = resource self.id = id super().__init__(f"{resource} {id} not found")
def get_user(user_id: int) -> dict: user = db.find(user_id) if user is None: raise NotFoundError("User", user_id) return user
|
断言 assert
开发阶段检查不变量,生产环境可用 -O 禁用:
1
| assert len(items) > 0, "items must not be empty"
|
不要用 assert 做业务逻辑校验或用户输入验证,应显式 raise。
上下文管理器
自动释放资源(详见装饰器章节):
1 2 3
| with open("data.txt", encoding="utf-8") as f: content = f.read()
|
最佳实践
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| try: value = int(user_input) except ValueError: value = 0
try: risky() except: pass
try: data = load_config() except FileNotFoundError: data = default_config() else: validate(data)
|
小结
- 捕获具体异常类型,避免裸
except
- 自定义异常继承自
Exception,按业务分层
raise ... from ... 保留异常链便于调试
- 资源管理优先用
with 语句