当前位置: 首页 > news >正文

python基础入门:6.3异常处理机制

Python异常处理全面指南:构建健壮程序的关键技术

# 完整异常处理模板
def process_file(file_path):"""文件处理示例函数"""file = Nonetry:file = open(file_path, 'r', encoding='utf-8')data = json.load(file)if not data:raise EmptyDataError("文件内容为空")  # 自定义异常result = complex_processing(data)  # 可能抛出多种异常except FileNotFoundError as e:logging.error(f"文件不存在: {e}")raise  # 重新抛出异常except json.JSONDecodeError as e:raise InvalidFormatError("JSON格式错误") from eexcept EmptyDataError as e:logging.warning(e)return Noneelse:logging.info("文件处理成功")return resultfinally:if file is not None:try:file.close()except IOError as e:logging.error(f"关闭文件失败: {e}")
一、异常处理结构详解
  1. 完整结构流程图
开始
↓
try
├─ 可能抛出异常的代码
↓
except
├─ 捕获指定异常
↓
else (可选)
├─ 无异常时执行
↓
finally (可选)
└─ 始终执行的清理代码
  1. 执行顺序示例
def division_test(value):try:print("try块开始")result = 10 / valueexcept ZeroDivisionError:print("捕获除零错误")except TypeError:print("捕获类型错误")else:print("计算结果:", result)finally:print("finally块执行")# 测试用例
division_test(2)  # 正常执行
division_test(0)  # 触发ZeroDivisionError
division_test("a") # 触发TypeError
  1. 各代码块使用场景
代码块典型用途最佳实践
try包裹可能出错的代码尽量缩小代码范围
except处理特定异常明确指定异常类型,避免裸露except
else执行依赖try成功的操作将与try相关的后续操作放在else中
finally资源清理(文件/网络连接)确保关闭资源的代码必须放在此处
二、自定义异常与异常链
  1. 自定义异常类模板
class AppBaseError(Exception):"""应用基础异常类"""def __init__(self, message="应用错误", code=1000):self.code = codeself.message = messagesuper().__init__(self.message)class NetworkError(AppBaseError):"""网络相关异常"""def __init__(self, url, status_code):super().__init__(message=f"网络请求失败: {url} (状态码: {status_code})",code=2001)self.url = urlself.status_code = status_codeclass DatabaseError(AppBaseError):"""数据库操作异常"""ERROR_CODES = {1452: "外键约束失败",1062: "重复键值"}def __init__(self, sql, errcode):code = 3000 + errcodemsg = f"SQL执行错误: {self.ERROR_CODES.get(errcode, '未知错误')}"super().__init__(message=msg, code=code)self.sql = sql
  1. 异常链实践
def fetch_data():try:response = requests.get('https://api.example.com/data', timeout=5)response.raise_for_status()return response.json()except requests.RequestException as e:raise DataFetchError("数据获取失败") from e  # 保留原始异常信息try:data = fetch_data()
except DataFetchError as e:print(f"错误原因: {e}")print(f"原始异常: {e.__cause__}")  # 显示底层网络异常
三、断言与防御性编程
  1. 断言使用规范
def calculate_discount(price, discount):"""计算商品折扣价"""# 前置条件检查assert isinstance(price, (int, float)), "价格必须是数值"assert 0 <= discount <= 1, "折扣率应在0-1之间"# 业务逻辑discounted = price * (1 - discount)# 后置条件验证assert discounted <= price, "折后价不应超过原价"return discounted# 测试断言
try:calculate_discount(100, 0.2)  # 正常calculate_discount("100", 0.5) # 触发类型断言
except AssertionError as e:print(f"输入验证失败: {e}")
  1. 防御性编程技巧
def safe_divide(a, b):"""安全的除法运算"""# 输入验证if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):raise TypeError("操作数必须是数值类型")# 边界条件检查if b == 0:raise ValueError("除数不能为零")# 类型转换result = float(a) / float(b)# 结果验证if math.isinf(result):raise OverflowError("计算结果溢出")return round(result, 4)
四、异常处理最佳实践
  1. 异常处理决策树
出现错误情况
↓
是否属于正常业务流程? → 是 → 使用返回码/状态标识
↓
否
↓
是否可恢复? → 是 → 捕获处理
↓
否
↓
抛出异常终止流程
  1. 异常日志规范
import logging
import tracebacklogger = logging.getLogger(__name__)try:risky_operation()
except (NetworkError, DatabaseError) as e:logger.error(f"操作失败 [代码:{e.code}]: {e.message}")
except Exception as e:logger.critical(f"未处理的异常: {str(e)}\n"f"堆栈跟踪: {traceback.format_exc()}")raise
  1. 性能优化建议
  • 避免在频繁执行的代码路径中使用try块
  • 将异常处理移到循环外部
  • 使用预检查替代异常捕获(LBYL vs EAFP)
# 低效方式
for num in numbers:try:value = 10 / numexcept ZeroDivisionError:value = 0# 高效方式
processed = []
for num in numbers:if num == 0:processed.append(0)else:processed.append(10/num)

异常处理反模式

# 错误1:吞噬所有异常
try:do_something()
except:pass# 错误2:过于宽泛的异常捕获
try:process_data()
except Exception as e:handle_error()# 错误3:重复的异常处理
try:file.read()
except IOError:file.close()try:file.write()
except IOError:file.close()# 正确方式:使用上下文管理器
with open('file.txt') as f:process(f)

调试建议

# 在开发环境启用详细调试
if DEBUG:import pdbpdb.set_trace()# 使用__debug__优化生产代码
if __debug__:print("调试信息")
else:logging.info("生产日志")
开始执行
可能出错?
使用try包裹
正常流程
发生异常?
匹配except块
记录日志
处理/转换异常
是否需要中断流程
抛出新异常
恢复执行
执行else块
正常返回结果
外层捕获处理
最终清理
结束
http://www.lryc.cn/news/535357.html

相关文章:

  • Mybatis快速入门与核心知识总结
  • 畅聊deepseek-r1,SiliconFlow 硅基流动注册+使用
  • 一个基于ESP32S3和INMP441麦克风实现音频强度控制RGB灯带律动的代码及效果展示
  • Springboot 中如何使用Sentinel
  • 访问Elasticsearch服务 curl ip 端口可以 浏览器不可以
  • Curser2_解除机器码限制
  • 人工智能与低代码如何重新定义企业数字化转型?
  • arkTS基础
  • C++20中的std::atomic_ref
  • 四、自然语言处理_08Transformer翻译任务案例
  • spring学习(使用spring加载properties文件信息)(spring自定义标签引入)
  • bigemap pro如何进行poi兴趣点搜索?
  • Mybatis源码02 - 初始化基本过程(引导层部分)
  • 【Elasticsearch】bucket_sort
  • k8s证书过期怎么更新?
  • 活动预告 |【Part 1】Microsoft 安全在线技术公开课:通过扩展检测和响应抵御威胁
  • AIGC-微头条爆款文案创作智能体完整指令(DeepSeek,豆包,千问,Kimi,GPT)
  • C# 比较两个List集合内容是否相同
  • vue2 多页面pdf预览
  • 【python】matplotlib(animation)
  • Hello Robot 推出Stretch 3移动操作机器人,赋能研究与商业应用
  • 从零到一:我的元宵灯谜小程序诞生记
  • Docker 安装与配置 Nginx
  • Oracle常见语法
  • 在Vue3中使用Echarts的示例 两种方法
  • 【docker】docker改动镜像并重新编译举例
  • 具身智能训练新思路!将生成视频用于训练机器人
  • 15、深度学习-自学之路-反向传播程序展示、激活函数的应用,反向权重的更新、2层神经网络的应用,输入输出相关性的理解。
  • 【JavaEE进阶】依赖注入 DI详解
  • 医疗影响分割 | 使用 Swin UNETR 训练自己的数据集(3D医疗影像分割教程)