枪战英雄
99.99M · 2026-03-28
raise ValueError("输入格式有误") # 抛出内置异常
raise ValueError() # 使用默认消息 # 抛出异常实例
Python 的 优雅 异常链(Exception Chaining)语法,用于将一个异常与另一个异常关联起来。
用例展示
# 优势:不同层看到不同抽象级别的异常!
# 按层次定义异常
class UserError(Exception):
"""用户层异常(直接展示给用户)"""
pass
class BusinessError(Exception):
"""业务层异常(记录日志,转换为UserError)"""
pass
class DataError(Exception):
"""数据层异常(记录详细日志)"""
pass
# 数据层
def save_to_database(data):
try:
db.insert(data)
except DatabaseError as e:
raise DataError(f"数据库操作失败: {e}") from e # 原始异常会被附加为新异常的 __cause__
# 业务层
def process_user_order(order):
try:
save_to_database(order)
send_notification(order)
except DataError as e:
log_error(e) # 记录技术细节
raise UserError("订单处理失败,请联系客服") from e # 转换为用户友好的异常
# 用户层(展示给用户)
def handle_request():
try:
process_user_order(order_data)
except UserError as e:
show_error_message(str(e)) # 显示友好信息
except Exception as e:
log_error(e)
show_error_message("系统错误,请稍后重试")
def divide(a: float, b: float) -> float:
if b == 0:
raise ZeroDivisionError("除数不能为 0")
return a / b
# 捕获单个异常
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"捕获到异常: {e}")
# 捕获多个异常
try:
value = int("abc")
except (ValueError, TypeError) as e:
print(f"类型或值错误: {e}")
# 捕获所有 Exception类 异常(一股脑/未拆分,不推荐)
try:
risky_operation()
except Exception as e:
print(f"发生异常: {e}")
try:
# 可能抛出异常的代码
result = 10 / 0
except ZeroDivisionError as e:
# 捕获特定异常
print(f"除零错误: {e}")
except ValueError as e:
# 捕获另一种异常
print(f"值错误: {e}")
else:
# 没有异常时执行
print("计算成功")
finally:
# 无论是否异常都执行
print("清理资源")
# 自动管理资源
# 多个上下文管理器
with open("input.txt", "r") as fin, open("output.txt", "w") as fout:
data = fin.read()
fout.write(processed_data)
from contextlib import contextmanager
@contextmanager
def database_transaction():
"""数据库事务上下文管理器"""
conn = connect_database()
try:
yield conn
conn.commit()
except Exception:
conn.rollback()
raise
finally:
conn.close()
# 使用
with database_transaction() as conn:
conn.execute("INSERT INTO users VALUES (?, ?)", ("Alice", 25))
try:
raise ValueError("自定义错误消息")
except ValueError as e:
print(f"消息: {e}") # 异常消息
print(f"类型: {type(e).__name__}") # 异常类型
print(f"参数: {e.args}") # 异常参数
print(f"字符串: {str(e)}") # 异常的字符串表示
print(f"Repr: {repr(e)}") # 异常的 repr
def function_c():
raise ValueError("底层错误")
def function_b():
function_c() # 异常从这里开始传播
def function_a():
try:
function_b()
except ValueError as e:
print(f"在 function_a 中捕获: {e}")
function_a() # 输出: 在 function_a 中捕获: 底层错误
# function 是 标准 拼写 !!
import traceback
try:
raise ValueError("测试异常")
except Exception:
traceback.print_exc() # 打印完整的异常回溯
tb_info = traceback.format_exc() # 获取回溯信息
print(f"异常信息:n{tb_info}")
import logging
logger = logging.getLogger(__name__)
try:
risky_operation()
except Exception as e:
logger.error("操作失败", exc_info=True) # 记录异常,包含堆栈信息
logger.exception("操作失败") # 或简写形式
# 捕获特定的异常
try:
data = parse_json(json_string)
except json.JSONDecodeError as e:
logger.error(f"JSON 解析失败: {e}")
handle_error()
# 提供有意义的错误消息
raise ValueError(f"年龄 {age} 无效,必须在 0 到 150 之间")
# 使用异常链保留上下文
try:
load_config()
except IOError as e:
raise RuntimeError("无法加载配置") from e
# 在文档中声明可能抛出的异常
def connect_database(url: str) -> Connection:
"""
连接到数据库
Raises:
ConnectionError: 连接失败时抛出
TimeoutError: 连接超时时抛出
"""
pass
# 捕获所有异常但不处理
try:
do_something()
except:
pass # 吞掉所有异常
# 使用裸 except
try:
do_something()
except: # 应该指定异常类型
pass
# 过于宽泛的异常捕获
try:
process_data()
except Exception: # 应该捕获更具体的异常
pass
# 忽略异常信息
try:
risky_operation()
except ValueError:
pass # 没有记录或处理异常信息
场景 示例 原因
1. 业务领域错误 订单不存在、库存不足 更清晰表达业务逻辑
2. 需要携带额外信息 错误代码、上下文数据 内置异常无法承载
3. 分层异常处理 控制层、服务层、数据层 不同层处理不同异常
4. 框架/库开发 Web框架、ORM 用户需要区分你的异常
5. 需要特定恢复逻辑 重试、降级 不同异常不同处理方式
# 项目中的异常继承层次(参考项目代码)
class AgentError(Exception):
"""Agent 基础异常类, 后续异常类均继承于此,便于管理"""
pass
class ToolExecutionError(AgentError):
"""工具执行异常"""
pass
class ToolValidationError(AgentError):
"""工具参数验证异常"""
pass
class APIError(AgentError):
"""API 调用异常"""
pass
class MaxIterationsExceededError(AgentError):
"""超过最大迭代次数异常"""
pass
class MyError(Exception):
"""自定义异常基类""" # 继承自Exception
pass
class SimpleError(MyError):
pass
class MyError(Exception):
"""自定义异常基类""" # 继承自Exception
pass
class DetailedError(MyError):
def __init__(self, message: str, code: int):
self.message = message
self.code = code
super().__init__(f"错误 {code}: {message}")
class MyError(Exception):
"""自定义异常基类""" # 继承自Exception
pass
class FullFeaturedError(MyError):
def __init__(self, message: str, details: dict):
self.message = message
self.details = details
super().__init__(message)
def __str__(self):
return f"[{self.message}] 详情: {self.details}"
def get_details(self):
return self.details
如需抛出异常时自动处理某些参数,或者给异常绑定特定的变量,则需要替换 pass 为具体代码(通常是 init 方法)。代码示例如下
class MyError(Exception):
"""这里需要替换 pass,填写具体逻辑"""
def __init__(self, message, error_code, tm):
super().__init__(message) # 初始化父类
self.error_code = error_code # 添加自定义属性
self.tm = tm
# 封装 raise 逻辑
def fail_fast(message, error_code, tm):
# raise 依然存在于这里,只是被藏起来了
raise MyError(message, error_code, tm)
# 异常抛出的使用
from datetime import datetime
try:
'''
常规函数体,及判定逻辑
可以结合 if 等判定逻辑进行
'''
current_datetime = datetime.now() # 获取当前的日期和时间
formatted_datetime = current_datetime.strftime("%Y-%m-%d %H:%M:%S.%f")[:] # 将datetime对象转换为自定义的字符串格式
raise MyError("系统崩溃了", 500, formatted_datetime)
# 或者 fail_fast("系统崩溃了", 500, formatted_datetime)
except MyError as e:
print(f"错误信息: {e}, 错误代码: {e.error_code}, 错误时间:{e.tm}")
类的 __str__(self) 魔术方法的使用
# 定义自定义异常类
class MyError(Exception):
"""自定义异常基类"""
pass
class APIError(MyError):
"""API 调用异常"""
# 构造方法,创建对象时自动调用,初始化对象属性
def __init__(self, message: str, status_code: int = None):
super().__init__(message) # 调用父类的 __init__ 方法
self.status_code = status_code # 然后再添加子类特有属性
# Python 一个特殊方法(魔术方法),用于定义对象的字符串表示形式。
# 当需要将对象转换为字符串时,Python 会自动调用 __str__() 方法:
def __str__(self):
if self.status_code: # 处置灵活
return f"API错误 {self.status_code}: {self.message}"
return f"API错误: {self.message}"
# 使用自定义异常
try:
raise APIError("网络请求失败", status_code=500)
except APIError as e:
print(e) # API错误 500: 网络请求失败
__str__() 的 8 种自动触发条件
obj = SomeObject()print(obj) # ← 触发 __str__()
obj = SomeObject()str_obj = str(obj) # ← 触发 __str__()
obj = SomeObject()message = f"结果: {obj}" # ← 触发 __str__()
obj = SomeObject()message = "结果: {}".format(obj) # ← 触发 __str__()
obj = SomeObject()message = "结果: %s" % obj # ← 触发 __str__()
obj = SomeObject()message = "结果: " + str(obj) # ← str() 触发 __str__()
import loggingobj = SomeObject()logging.info(f"日志信息: {obj}") # ← 触发 __str__()
def get_description(obj): return f"描述: {obj}" # ← 触发 __str__()
捕捉异常进一步响应后,抛出捕获的异常,或向上传递
def main() -> None:
"""演示异常的使用和处理。"""
try:
current_datetime = datetime.now() # 模拟业务逻辑
formatted_datetime = current_datetime.isoformat()
raise MyError("系统崩溃了", 500, formatted_datetime) # 抛出异常
except MyError as e:
print(f"错误代码: {e.error_code}") # 记录错误信息
raise # 向上传递异常
# [或者] raise 新异常 from 原始异常
if __name__ == "__main__":
try:
main()
except MyError as e:
print(f"n最终捕获的错误: {e}")
print(f"错误代码: {e.error_code}")
print(f"错误时间: {e.timestamp}")
自定义异常抛出 raise
概括
优势1:语义更清晰
# 使用内置异常(不清晰)
def divide(a, b):
if b == 0:
raise ValueError("除数不能为零") # 太泛化
# 使用自定义异常(清晰)
class DivisionByZeroError(Exception):
"""除零错误"""
pass
def divide(a, b):
if b == 0:
raise DivisionByZeroError(f"{a} 不能除以 {b}") # 语义明确
# 使用时
try:
result = divide(10, 0)
except DivisionByZeroError:
print("除零错误,请检查输入") # 精确处理
except ValueError:
print("其他参数错误")
优势2:携带额外上下文
# 优势:内置异常无法这样携带结构化数据!
class ToolExecutionError(Exception):
"""工具执行异常"""
def __init__(self, tool_name: str, error: str):
self.tool_name = tool_name # 额外信息:工具名
self.error = error # 额外信息:错误详情
super().__init__(f"工具 '{tool_name}' 执行失败: {error}")
# 使用
try:
execute_tool("add", {"a": 1, "b": "two"})
# 函数体内需要能够 raise ToolExecutionError,自定义 异常抛出 使用时的前置条件
except ToolExecutionError as e:
print(f"工具: {e.tool_name}") # 访问额外信息
print(f"错误: {e.error}")
# 可以针对不同工具采取不同恢复策略
if e.tool_name == "add":
retry_with_defaults()
else:
log_error()
优势3:精确的异常捕获
# 定义异常层次
class AgentError(Exception):
"""Agent基础异常"""
pass
class ToolError(AgentError):
"""工具相关异常"""
pass
class APIError(AgentError):
"""API相关异常"""
pass
class ConfigError(AgentError):
"""配置相关异常"""
pass
# 精确捕获
try:
agent.run()
except ToolError:
print("工具错误,重试...")
except APIError:
print("API错误,切换备用服务器...")
except ConfigError:
print("配置错误,请检查配置文件")
except AgentError:
print("其他Agent错误")
# 所有都可能是ValueError,无法区分
try:
agent.run()
except ValueError as e:
# 这个ValueError可能是工具错误、API错误或配置错误
# 无法精确处理!
print("发生错误:", e)
优势4:分层异常处理 ️
# 优势:不同层看到不同抽象级别的异常!
# 按层次定义异常
class UserError(Exception):
"""用户层异常(直接展示给用户)"""
pass
class BusinessError(Exception):
"""业务层异常(记录日志,转换为UserError)"""
pass
class DataError(Exception):
"""数据层异常(记录详细日志)"""
pass
# 数据层
def save_to_database(data):
try:
db.insert(data)
except DatabaseError as e:
raise DataError(f"数据库操作失败: {e}") from e
# 业务层
def process_user_order(order):
try:
save_to_database(order)
send_notification(order)
except DataError as e:
log_error(e) # 记录技术细节
raise UserError("订单处理失败,请联系客服") from e # 转换为用户友好的异常
# 用户层(展示给用户)
def handle_request():
try:
process_user_order(order_data)
except UserError as e:
show_error_message(str(e)) # 显示友好信息
except Exception as e:
log_error(e)
show_error_message("系统错误,请稍后重试")
优势5:框架/库的API设计
# 优势:库使用者可以精确区分不同错误类型!
# 作为一个库作者,提供清晰的异常接口
class DataProcessor:
"""数据处理库"""
class DataFormatError(Exception):
"""数据格式错误"""
pass
class ValidationError(Exception):
"""数据验证错误"""
pass
class ProcessingError(Exception):
"""处理过程错误"""
pass
def process(self, data):
if not self._validate_format(data):
raise DataFormatError("数据格式不正确")
if not self._validate_content(data):
raise ValidationError("数据内容不符合要求")
if not self._process_data(data):
raise ProcessingError("处理过程失败")
# 库使用者
processor = DataProcessor()
try:
processor.process(user_data)
except DataFormatError:
print("请提供正确格式的数据")
except ValidationError:
print("数据内容有误")
except ProcessingError:
print("处理失败,请重试")
方式2更清晰、更易维护
# ========== 方式1:只用内置异常 ==========
def register_user(username, email, password):
if not username:
raise ValueError("用户名不能为空")
if '@' not in email:
raise ValueError("邮箱格式错误")
if len(password) < 8:
raise ValueError("密码长度不足")
# ... 注册逻辑
# 使用时
try:
register_user("", "invalid", "short")
except ValueError as e:
# 所有错误都是ValueError,无法区分
print("注册失败:", e)
# 如何知道是哪个字段错了?需要解析字符串,很脆弱!
# ========== 方式2:使用自定义异常 ==========
class RegistrationError(Exception):
"""注册异常基类"""
pass
class UsernameError(RegistrationError):
"""用户名错误"""
pass
class EmailError(RegistrationError):
"""邮箱错误"""
pass
class PasswordError(RegistrationError):
"""密码错误"""
pass
def register_user(username, email, password):
if not username:
raise UsernameError("用户名不能为空")
if '@' not in email:
raise EmailError("邮箱格式错误")
if len(password) < 8:
raise PasswordError("密码长度不足")
# ... 注册逻辑
# 使用时
try:
register_user("", "invalid", "short")
except UsernameError:
print("请输入用户名")
except EmailError:
print("请输入有效的邮箱地址")
except PasswordError:
print("密码长度至少8位")
except RegistrationError:
print("注册失败,请检查输入")
四大系统级异常 (直接继承BaseException)
异常类型 触发场景 代码设计建议捕获 原因
Exception 所有常规异常的父类 其子类 应该 常规程序错误,应该处理
KeyboardInterrupt 用户按 Ctrl+C ️ 谨慎 仅用于清理资源,不要完全忽略
SystemExit sys.exit() 调用 不建议 让程序正常退出,除非有特殊需求
GeneratorExit 生成器关闭 不需要 生成器内部通常不需要处理
简化结构
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
├── Exception
├── StopIteration
├── ArithmeticError
│ ├── ZeroDivisionError
│ └── FloatingPointError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── OSError
├── ValueError
├── TypeError
└── RuntimeError
基本层级架构逻辑为
BaseException (顶层)
↓
Exception (中层 - 用户可捕获的异常)
↓
具体异常类 (底层 - 具体错误类型)
Exception本身不会直接被抛出,但可以用try-except捕获所有继承自Exception的异常。
Exception 类捕获 代码示例
# 捕获 Exception 本身
try:
# 任何继承自 Exception 的异常都会被捕获
raise ValueError("值错误")
except Exception as e:
print(f"捕获到Exception子类: {type(e).__name__}")
print(f"消息: {e}")
# 捕获 Exception 的子类
try:
raise ValueError("值错误")
except ValueError as e: # ValueError 是 Exception 的子类
print(f"捕获到 ValueError: {e}")
# 捕获多个异常类
try:
raise TypeError("类型错误")
except (ValueError, TypeError, KeyError) as e:
print(f"捕获到异常: {e}")
Exception 子类 by 功能领域的不完全分组:
算术域
ArithmeticError # 算术错误
├── FloatingPointError # 精度问题
├── OverflowError # 范围溢出
└── ZeroDivisionError # 除零错误
查找域
LookupError # 查找错误
├── IndexError # 序列索引错误
└── KeyError # 映射键错误
I/O 域
OSError (大量子类)
├── FileNotFoundError # 文件不存在
├── PermissionError # 权限问题
├── TimeoutError # 超时
└── ... (更多系统错误)
ValueError - 值错误
TypeError - 类型错误
AttributeError - 属性错误
import math
math.sqrt("abc") # math 对象没有 sqrt 属性(实际上有,但参数类型错误)
ImportError - 导入错误
ImportError # 模块导入失败
└── ModuleNotFoundError # 找不到模块
RuntimeError - 运行时错误
RuntimeError # 运行时错误基类
├── NotImplementedError # 未实现的方法
└── RecursionError # 递归深度超限
同类错误归为一组,便于批量捕获(如 except LookupError: 同时处理IndexError和KeyError)。
```python
BaseException
├── SystemExit # sys.exit()引发
├── KeyboardInterrupt # 用户中断执行(Ctrl+C)
├── GeneratorExit # 生成器关闭时引发
└── Exception # 所有用户定义异常的基类
├── StopIteration # 迭代器没有更多值
├── StopAsyncIteration # 异步迭代器
├── ArithmeticError # 算术错误基类
│ ├── FloatingPointError # 浮点计算失败
│ ├── OverflowError # 数值溢出
│ └── ZeroDivisionError # 除以零
├── AssertionError # assert语句失败
├── AttributeError # 属性引用失败
├── BufferError # 缓冲区操作失败
├── EOFError # 输入结束
├── ImportError # 模块导入失败
│ └── ModuleNotFoundError # 找不到模块
├── LookupError # 查找失败基类
│ ├── IndexError # 索引超出范围
│ └── KeyError # 字典键不存在
├── MemoryError # 内存不足
├── NameError # 局部/全局名称不存在
│ └── UnboundLocalError # 访问未初始化的局部变量
├── OSError # 操作系统错误基类
│ ├── BlockingIOError # 操作会阻塞
│ ├── ChildProcessError # 子进程操作失败
│ ├── ConnectionError # 连接相关错误基类
│ │ ├── BrokenPipeError # 管道破裂
│ │ ├── ConnectionAbortedError
│ │ ├── ConnectionRefusedError
│ │ └── ConnectionResetError
│ ├── FileExistsError # 文件已存在
│ ├── FileNotFoundError # 文件未找到
│ ├── InterruptedError # 系统调用中断
│ ├── IsADirectoryError # 操作目录而非文件
│ ├── NotADirectoryError # 操作文件而非目录
│ ├── PermissionError # 权限不足
│ └── TimeoutError # 操作超时
├── ReferenceError # 弱引用访问已删除对象
├── RuntimeError # 运行时错误基类
│ ├── NotImplementedError # 未实现的方法
│ └── RecursionError # 递归深度超限
├── SyntaxError # 语法错误
│ └── IndentationError # 缩进错误
│ └── TabError # Tab和空格混用
├── SystemError # 解释器内部错误
├── TypeError # 类型错误
├── ValueError # 值错误
└── Warning # 警告基类
├── DeprecationWarning
├── PendingDeprecationWarning
├── RuntimeWarning
├── SyntaxWarning
├── UserWarning
├── FutureWarning
├── ImportWarning
├── UnicodeWarning
└── BytesWarning
```