5.1 异常处理基础
引言
小白理解 - 什么是异常?
异常 = 程序运行时出现的错误
类比:开车时遇到的各种意外
意外情况 对应的 Python 异常 除以零 ZeroDivisionError文件不存在 FileNotFoundError参数类型错了 TypeError列表下标越界 IndexError网络超时 TimeoutError不处理异常:程序直接崩溃,显示红色错误信息 处理异常:捕获错误,优雅处理或提示用户
try/except/finally
小白理解 - try/except/finally 的结构
pythontry: # 尝试执行可能出错的代码 危险操作() except 某种错误: # 如果出错了,执行这里 处理错误() finally: # 不管有没有出错,最后都执行这里 清理工作()类比:拆快递
pythontry: 打开快递盒() # 可能失败(盒子打不开) except 打不开Error: 用剪刀剪开() # 备用方案 finally: 把包装纸扔垃圾桶() # 不管怎样都要收拾
python
def call_api(endpoint: str) -> dict:
"""调用 API(带异常处理)"""
try:
# 模拟 API 调用
if not endpoint:
raise ValueError("端点不能为空")
# 实际调用逻辑
response = {"status": "success", "data": {}}
return response
except ValueError as e:
print(f"参数错误: {e}")
return {"status": "error", "message": str(e)}
except Exception as e:
print(f"未知错误: {e}")
return {"status": "error", "message": "系统错误"}
finally:
print("API 调用完成")
# 使用
result = call_api("")代码解读:
代码 含义 try:开始"尝试"执行可能出错的代码 raise ValueError(...)主动抛出一个错误 except ValueError as e:如果是 ValueError,执行这里,e 是错误详情 except Exception as e:其他所有错误都走这里(兜底) finally:无论如何都会执行(清理资源) 执行顺序:
1. 执行 try 里的代码 2. 如果出错 → 跳到对应的 except 3. 如果没出错 → 跳过所有 except 4. 最后执行 finally(必执行)
常见异常类型
小白理解 - 常见错误速查表
错误类型 什么时候出现 例子 ValueError值不对 int("abc")TypeError类型不对 "hello" + 123KeyError字典键不存在 d["不存在的键"]IndexError列表下标越界 [1,2,3][10]FileNotFoundError文件不存在 open("不存在.txt")ZeroDivisionError除以零 1 / 0AttributeError属性不存在 "hello".不存在的方法()TimeoutError超时 网络请求太久
自定义异常
小白理解 - 为什么要自定义异常?
Python 内置的异常(如 ValueError)太"通用"了
问题:你调用 API 出错,但不知道是哪种错误
pythonexcept Exception as e: # 是网络错误?密钥错误?还是参数错误? # 只能看 e 的文字描述,不方便区分解决:创建专属的错误类型
pythonexcept APIKeyError: # 肯定是密钥问题 → 提示用户检查密钥 except NetworkError: # 肯定是网络问题 → 自动重试自定义异常 = 给错误贴上明确的"标签"
小白理解 - 如何创建自定义异常?
pythonclass 我的错误(Exception): # 继承 Exception pass # 最简单的写法,空着就行 # 使用 raise 我的错误("错误信息")异常继承树:
Exception(Python 内置) └── AgentError(你创建的基类) ├── ModelNotFoundError(具体错误) └── APIKeyError(具体错误)
python
class AgentError(Exception):
"""Agent 基础异常"""
pass
class ModelNotFoundError(AgentError):
"""模型未找到"""
pass
class APIKeyError(AgentError):
"""API 密钥错误"""
pass
def create_agent(model: str, api_key: str):
if not api_key:
raise APIKeyError("API 密钥未配置")
if model not in ["gpt-4", "gpt-3.5-turbo"]:
raise ModelNotFoundError(f"模型 {model} 不存在")
return {"model": model, "status": "ready"}
# 使用
try:
agent = create_agent("gpt-5", "")
except APIKeyError as e:
print(f"密钥错误: {e}")
except ModelNotFoundError as e:
print(f"模型错误: {e}")最佳实践:
python# 1. 创建一个基类异常 class AgentError(Exception): pass # 2. 所有具体异常继承自基类 class APIKeyError(AgentError): pass class ModelError(AgentError): pass # 3. 这样可以一次捕获所有 Agent 相关错误 except AgentError as e: # 捕获所有子类错误 处理错误()
实战:带重试的 API 调用
小白理解 - 为什么需要重试?
API 调用可能因为网络波动失败,但下一秒可能就好了
没有重试:一次失败就放弃 有重试:失败了再试几次,大大提高成功率
python
import time
from typing import Callable, Any
def retry(max_attempts: int = 3, delay: float = 1.0):
"""重试装饰器"""
def decorator(func: Callable) -> Callable:
def wrapper(*args, **kwargs) -> Any:
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt < max_attempts - 1:
print(f"第 {attempt + 1} 次失败,{delay}秒后重试...")
time.sleep(delay)
else:
print(f"重试 {max_attempts} 次后仍失败")
raise
return wrapper
return decorator
@retry(max_attempts=3, delay=1.0)
def call_llm_api(prompt: str) -> str:
"""调用 LLM API(带自动重试)"""
# 实际 API 调用逻辑
return f"Response to: {prompt}"本节小结
| 概念 | 一句话解释 | 记忆口诀 |
|---|---|---|
| try | 尝试执行可能出错的代码 | try = 试试看 |
| except | 捕获并处理错误 | except = 接住错误 |
| finally | 无论如何都执行 | finally = 最后收拾 |
| raise | 主动抛出错误 | raise = 报警 |
| 自定义异常 | 创建专属的错误类型 | 继承 Exception |
新手常见问题
Q1:except Exception 和 except 有什么区别?
except Exception:捕获所有"普通"异常except::捕获所有异常(包括系统退出),不推荐Q2:什么时候用 finally?
- 关闭文件、数据库连接
- 释放网络资源
- 任何"必须执行的清理工作"
Q3:应该捕获所有异常吗?
- 不!只捕获你能处理的
- 让不能处理的异常继续向上传播
下一节:5.2 日志系统