🎯 高级魔法师实战:异常处理进阶练习
🎉 欢迎来到异常处理进阶的练习环节!通过这些练习,你将巩固Python异常处理的高级特性,掌握自定义异常、上下文管理器、异常链等实用技巧,让你的代码更加健壮可靠。
🎯 练习目标
完成这些练习后,你将能够:
- 熟练掌握异常的捕获、处理和传播机制
- 创建和使用自定义异常类及其层次结构
- 设计和实现自定义上下文管理器
- 应用异常处理的最佳实践
- 处理实际应用场景中的异常情况
📝 基础练习
练习1:异常的捕获与处理
任务:编写一个函数 calculate_average(numbers),用于计算列表中所有数字的平均值。函数需要处理以下异常情况:
- 如果输入不是列表,抛出
TypeError异常 - 如果列表为空,抛出
ValueError异常 - 如果列表中包含非数字元素,跳过这些元素并继续计算
- 如果过滤后没有有效数字,返回
None并打印提示信息
示例:
# 正常情况
average = calculate_average([1, 2, 3, 4, 5])
print(average) # 输出: 3.0
# 包含非数字元素
average = calculate_average([1, 2, "three", 4, 5])
print(average) # 输出: 3.0 (跳过了"three")
# 空列表
# calculate_average([]) # 应抛出 ValueError 异常
# 非列表输入
# calculate_average(123) # 应抛出 TypeError 异常练习2:自定义异常
任务:创建一个自定义异常层次结构,用于处理一个简单的在线商城系统中的错误情况。
- 创建基础异常类
ShoppingError - 创建两个子类:
ProductError和OrderError - 为每个子类创建更具体的异常,例如:
ProductNotFoundError(找不到商品)ProductOutOfStockError(商品缺货)OrderValidationError(订单验证错误)PaymentError(支付错误)
- 实现一个简单的函数
place_order(product_id, quantity),根据不同情况抛出相应的异常
要求:每个自定义异常都应该包含详细的错误信息,并且可以被单独捕获和处理。
练习3:异常链
任务:编写一个函数 read_configuration(filename),用于从配置文件中读取配置信息。函数需要:
- 尝试打开并读取指定的文件
- 使用
json模块解析文件内容 - 当发生异常时,创建异常链,保留原始异常信息
- 处理以下异常情况:
- 文件不存在 (
FileNotFoundError) -> 抛出ConfigurationError - 文件格式错误 (
json.JSONDecodeError) -> 抛出ConfigurationError - 权限错误 (
PermissionError) -> 抛出ConfigurationError
- 文件不存在 (
提示:使用 raise ... from 语法创建异常链。
练习4:上下文管理器
任务:创建一个自定义上下文管理器 TimerContext,用于测量代码块的执行时间。
要求:
- 实现
__enter__和__exit__方法 - 在
__enter__方法中记录开始时间 - 在
__exit__方法中计算并打印执行时间 - 确保即使代码块中发生异常,也能正确计算和显示执行时间
示例:
with TimerContext("执行计算"):
result = sum(i * i for i in range(1000000))
# 输出类似于: 执行计算: 0.1234秒练习5:使用 contextlib 创建上下文管理器
任务:使用 contextlib.contextmanager 装饰器创建一个名为 temporary_directory 的上下文管理器,用于:
- 创建一个临时目录
- 在
with语句块中使用这个目录 - 无论是否发生异常,在退出
with语句块时自动删除这个临时目录
提示:使用 tempfile 和 shutil 模块来创建和删除临时目录。
🚀 挑战题
挑战题1:文件操作上下文管理器
任务:创建一个高级文件操作上下文管理器 SafeFile,用于安全地进行文件读写操作。
要求:
- 支持
read、write和append三种模式 - 自动处理文件打开和关闭
- 提供有用的错误信息
- 支持
with语句的嵌套使用 - 实现自动备份功能:当以写模式打开文件时,自动创建文件的备份
示例:
with SafeFile("example.txt", mode="write") as file:
file.write("Hello, World!")
# 如果发生异常,文件仍会被正确关闭,并且原始文件(如果存在)会被备份挑战题2:数据库事务管理
任务:创建一个数据库事务管理上下文管理器 DatabaseTransaction,用于处理数据库事务。
要求:
- 支持自动提交和回滚功能
- 在
with语句块内执行的所有操作都在同一个事务中 - 如果
with语句块正常完成,自动提交事务 - 如果
with语句块中发生异常,自动回滚事务 - 提供清晰的错误信息和日志记录
示例:
with DatabaseTransaction(connection) as tx:
tx.execute("INSERT INTO users (name, email) VALUES (?, ?)", ("Alice", "alice@example.com"))
tx.execute("UPDATE accounts SET balance = balance - 100 WHERE user_id = ?", (1,))
# 如果两个操作都成功,自动提交事务;如果任一操作失败,自动回滚🔧 实践应用
应用场景:API 错误处理
任务:创建一个简单的 API 错误处理系统,用于处理 Web 应用中的各种错误情况。
要求:
- 创建一个完整的 API 异常层次结构
- 实现全局异常处理器,将异常转换为格式化的 JSON 响应
- 为不同类型的错误提供不同的 HTTP 状态码和错误信息
- 实现错误日志记录功能
- 提供详细的错误文档,帮助客户端开发者理解和解决问题
示例结构:
# 基础 API 异常
class APIException(Exception):
status_code = 500
error_code = "SERVER_ERROR"
message = "服务器内部错误"
def __init__(self, message=None, error_code=None, status_code=None):
if message: self.message = message
if error_code: self.error_code = error_code
if status_code: self.status_code = status_code
super().__init__(self.message)
# 特定类型的 API 异常
class BadRequestError(APIException):
status_code = 400
error_code = "BAD_REQUEST"
message = "请求参数错误"
class NotFoundError(APIException):
status_code = 404
error_code = "NOT_FOUND"
message = "请求的资源不存在"
# 更多异常类...
# 全局异常处理器(以 Flask 为例)
@app.errorhandler(APIException)
def handle_api_exception(error):
response = {
"error": {
"code": error.error_code,
"message": error.message
}
}
# 记录错误日志
logger.error(f"API Error: {error.error_code} - {error.message}", exc_info=True)
return jsonify(response), error.status_code💡 部分参考实现
练习1:异常的捕获与处理(参考实现)
def calculate_average(numbers):
if not isinstance(numbers, list):
raise TypeError("输入必须是列表类型")
if not numbers:
raise ValueError("列表不能为空")
valid_numbers = []
for item in numbers:
try:
# 尝试将元素转换为浮点数
valid_numbers.append(float(item))
except (ValueError, TypeError):
# 跳过非数字元素
continue
if not valid_numbers:
print("警告: 列表中没有有效的数字元素")
return None
return sum(valid_numbers) / len(valid_numbers)练习2:自定义异常(参考实现)
# 基础异常类
class ShoppingError(Exception):
"""购物系统基础异常"""
pass
# 商品相关异常
class ProductError(ShoppingError):
"""商品相关异常"""
pass
class ProductNotFoundError(ProductError):
"""商品未找到异常"""
def __init__(self, product_id):
self.product_id = product_id
message = f"找不到商品 ID: {product_id}"
super().__init__(message)
class ProductOutOfStockError(ProductError):
"""商品缺货异常"""
def __init__(self, product_id, requested_quantity, available_quantity):
self.product_id = product_id
self.requested_quantity = requested_quantity
self.available_quantity = available_quantity
message = f"商品 ID: {product_id} 缺货: request {requested_quantity}, available {available_quantity}"
super().__init__(message)
# 订单相关异常
class OrderError(ShoppingError):
"""订单相关异常"""
pass
class OrderValidationError(OrderError):
"""订单验证错误"""
def __init__(self, reason):
self.reason = reason
message = f"订单验证失败: {reason}"
super().__init__(message)
class PaymentError(OrderError):
"""支付错误"""
def __init__(self, payment_method, reason):
self.payment_method = payment_method
self.reason = reason
message = f"{payment_method} 支付失败: {reason}"
super().__init__(message)
# 简单的订单处理函数
def place_order(product_id, quantity):
# 模拟商品数据库
products = {
1: {"name": "笔记本电脑", "stock": 10},
2: {"name": "智能手机", "stock": 0},
# 商品 3 不存在
}
# 验证商品是否存在
if product_id not in products:
raise ProductNotFoundError(product_id)
# 验证商品库存
available_stock = products[product_id]["stock"]
if quantity > available_stock:
raise ProductOutOfStockError(product_id, quantity, available_stock)
# 验证订单数量
if quantity <= 0:
raise OrderValidationError("订单数量必须大于零")
# 模拟支付过程
try:
# 这里可以添加实际的支付逻辑
pass
except Exception as e:
raise PaymentError("信用卡", str(e))
# 订单成功
print(f"订单成功: 商品 ID {product_id}, 数量 {quantity}")
return {"order_id": 12345, "status": "success"}练习4:上下文管理器(参考实现)
import time
class TimerContext:
def __init__(self, label):
self.label = label
self.start_time = None
def __enter__(self):
self.start_time = time.time()
return self # 可以返回任意值,这里返回self供with语句使用
def __exit__(self, exc_type, exc_val, exc_tb):
end_time = time.time()
execution_time = end_time - self.start_time
print(f"{self.label}: {execution_time:.4f}秒")
# 返回False表示异常会继续传播
return False📚 学习资源推荐
- Python官方文档 - 异常处理:https://docs.python.org/zh-cn/3/tutorial/errors.html
- Real Python - Python 异常处理指南:https://realpython.com/python-exceptions/
- Python Cookbook - 异常处理:https://python3-cookbook.readthedocs.io/zh_CN/latest/chapters/p08_error_and_exceptions.html
- Effective Python - 第8条:学会使用 with 语句处理资源:https://effectivepython.com/2015/03/10/consider-coroutines-to-run-many-functions-concurrently
- Fluent Python - 第15章:上下文管理器和 else 块:https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/
恭喜你完成了异常处理进阶的所有练习!🎉 通过这些练习,你已经掌握了Python异常处理的高级技巧和最佳实践。在实际项目中,记得根据具体情况选择合适的异常处理策略,创建清晰、有意义的异常层次结构,并始终保持异常处理代码的简洁性和可维护性。 恭喜你完成了异常处理进阶的所有练习!🎉 通过这些练习,你已经掌握了Python异常处理的高级技巧和最佳实践。在实际项目中,记得根据具体情况选择合适的异常处理策略,创建清晰、有意义的异常层次结构,并始终保持异常处理代码的简洁性和可维护性。
异常处理是编写健壮软件的关键技能之一。良好的异常处理不仅可以使你的程序更加稳定可靠,还可以提供更好的用户体验和开发体验。继续加油,将这些知识应用到你的实际项目中吧!🚀




