Python异常处理:三种不同方法的探索与最佳实践

在这里插入图片描述

Python异常处理:三种不同方法的探索与最佳实践

前言

本文旨在探讨Python中三种不同的异常处理方法。通过深入理解各种异常处理策略,我们可以更好地应对不同的编程场景,选择最适合自己需求的方法。

异常处理在编程中扮演着至关重要的角色。合适的异常处理不仅可以提高代码的健壮性,还能增强程序的可读性和可维护性。在Python编程中,有效地管理异常是提高代码质量的关键一环。

在开始深入探讨之前,让我们先通过一个实际的编程难题来引入这个话题:


前天,一位朋友向我提出了一个问题。在处理一个循环遍历时,由于难以预见所有可能的错误,他需要为每个循环中的元素实现异常处理,以防某个元素的错误影响到整个程序的运行。

但这样做的结果是,代码因为过多的 try-except 块而变得冗长且难以维护。这种情况下,我们怎样才能优化代码,既处理异常又保持代码的清晰和简洁呢?

示例代码如下:

for item in html_xpath:
    try:
        try:
	        url = item.xpath('//title/url-ellipsis/a/url()')
        except Exception as e:
            url = None
        try:
            title = item.xpath('//title/text-ellipsis/a/text()')
        except Exception as e:
            title = None
        ...
    except Exception as e:
        ...

在本文中,我们将探讨三种不同的异常处理方法,并在最后回到这个问题,提供一个优化后的解决方案。


知识点📖📖

查阅这两篇文章,对食用本文更有帮助哦!!

  • 深入浅出Python异常处理 - 你所不知道的Python异常

  • 万字长文 - Python 日志记录器logging 百科全书 之 基础配置

在这里先总结下文中会介绍到的三种异常处理方法的优缺点以及应用场景:

方法优点缺点应用场景
try-except简单直接,易于理解。
针对不同类型的异常可以编写特定处理逻辑。
代码中频繁使用会导致代码冗长适用于处理已知可能发生的错误。
用于具体函数或代码块中的错误处理。
sys.excepthook全局捕获未处理的异常。
使用相对简单。
不能阻止程序因异常而终止。
仅处理未被 try-except 块捕获的异常。
在子线程中不适用。
适用于记录未捕获的异常。
错误报告和日志记录。
装饰器提高代码复用性和清晰度。
可定制化异常处理逻辑。
使用和理解需要更高的Python技能水平。
只适用于被装饰的函数。
适用于需要统一异常处理逻辑的函数。
用于减少代码重复,提高维护性。

异常处理方法总结✨✨

Python中有多种方式来处理异常,每种方法都适用于不同的情况和需求。

通过选择适当的异常处理方法,我们可以更好地管理和处理Python程序中的异常情况。

以下是三种常见的异常处理方法以及它们的优点和缺点:

1. 使用 try-except 块

优点:简单直接,易于理解;允许针对不同类型的异常编写特定的处理逻辑。

缺点:在代码中频繁重复使用可能导致代码冗长。

示例代码:

try:
    # 可能会引发异常的代码
    result = 1 / 0
except ZeroDivisionError:
    # 处理特定类型的异常
    print("不能除以零")
    

代码释义:

代码使用了 try-except 块来捕获特定类型的异常(ZeroDivisionError),且打印了一条错误消息。

代码运行效果如下:

在这里插入图片描述

2. 使用 sys.excepthook

sys.excepthookPython中的一个全局函数,它在脚本遇到未捕获的异常时被调用。默认情况下,当一个异常没有被任何 try-except 块捕获时,Python会调用 sys.excepthook,打印出异常信息以及堆栈跟踪。

优点:允许在程序的任何地方捕获未被处理的异常;使用起来相对简单。

缺点:不能阻止程序因未处理的异常而终止;只能用于处理未被 try-except 块捕获的异常。

示例代码:

import sys


def global_exception_handler(exc_type, exc_value, exc_traceback):
    print("完犊子咯!这里捕获了异常:", exc_value)


sys.excepthook = global_exception_handler

# 示例:故意制造一个除以零的错误
result = 1 / 0
print('没运行到这里哦!')

代码释义:

代码配置了 sys.excepthook,使其在未捕获的异常发生时,会调用 global_exception_handler 函数来处理异常。

它允许在程序的任何地方捕获未被处理的异常,但在捕获了未经处理的异常后程序会终止(优雅的退出。)

代码运行效果如下:

  • 可以看到,代码并没有运行到 print('没运行到这里哦!') 这一行~
    在这里插入图片描述

3. 使用装饰器

优点:提高代码的复用性和清晰度,减少重复代码;可以定制化异常处理逻辑,应用于特定的函数。

缺点:相较于直接的 try-except 块,装饰器的使用和理解需要更高的Python技能水平;只适用于被装饰的函数。

示例代码:

def catch_exceptions(func):
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            print(f"Exception caught in {func.__name__}: {e}")
            return None

    return wrapper


@catch_exceptions
def risky_function(x, y):
    return x / y


result = risky_function(1, 0)
print("程序继续执行")

代码释义:

代码定义了一个装饰器 catch_exceptions,它可以应用于所有需要处理的函数。当被装饰的函数抛出异常时,装饰器会捕获异常并打印错误消息。

代码运行效果如下:

  • 可以看到,程序在捕获了异常后,还可以正常向下执行~
    在这里插入图片描述

4. 更健壮的代码

这份代码在 使用装饰器 的基础上添加了堆栈打印和日志记录,而日志记录的作用,想必大家都很清楚了。

关于日志记录的使用,可以查阅俺前面的文章。

import logging
import traceback
import sys

# 配置日志记录器
logging.basicConfig(
    filename='app.log',
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    encoding='utf-8',
    filemode='w'
)


def catch_exceptions(func):
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            # 将异常信息记录到日志
            logging.error(f"Exception caught in {func.__name__}: {e}")
            logging.error(f"Exception type: {exc_type}")
            logging.error(f"Exception value: {exc_value}")
            log_traceback = ''.join(traceback.format_tb(exc_traceback))
            logging.error(f"Exception traceback: {log_traceback}")
            return None

    return wrapper


@catch_exceptions
def risky_function(x, y):
    return x / y  # 这里可能会引发 ZeroDivisionError


result = risky_function(1, 0)
print("程序继续执行")

代码运行效果如下:

  • 可以看到,日志记录的信息非常清晰。

在这里插入图片描述

解决前面的问题

这份代码解决了前面的问题,nice~

在这份代码中,我特地模拟了一段html文本,然后在 xpath_expression中特地使用了错误的表达式。
因代码只用作于演示,所以这里不添加日志记录和对战堆栈了~~

from lxml import html


# 定义异常处理装饰器
def catch_exceptions(func):
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            print(f"Exception caught in {func.__name__}: {e}")
            return '空'

    return wrapper


# 使用装饰器来解析HTML元素
@catch_exceptions
def parse_element(sub_element, xpath_expression):
    return sub_element.xpath(xpath_expression)


# 示例HTML元素
item_html = """
<div>
    <a href="https://frica.blog.csdn.net/?type=blog">frica Link</a>
    <span>是小菜欸</span>
    ...
</div>
"""

# 定义HTML元素与XPath的映射
html_xpath_map = {
    'url': "//a/@href",
    'title': "//span/text()",
    'other': '//dd/dd/ddd/text()',
    'age': '这不是xpath_expression表达式'
}

if __name__ == '__main__':
    result_map = dict()

    # 创建HTML元素对象
    element = html.fromstring(item_html)

    # 遍历XPath映射,解析元素并将结果存入字典
    for key, value in html_xpath_map.items():
        result = parse_element(element, value)
        result_map[key] = result[0] if result else '空'
        # 海象运算符
        # result_map[key] = x[0] if (x := parse_element(element, value)) else '空'

    # 打印解析结果
    print(result_map)

代码释义:

这份代码的主要目的是解决在循环遍历中处理异常的问题,

通过使用装饰器和Xpath来简化异常处理,并使代码更清晰和简洁。

总的来说,这份关于异常处理的代码已经很健壮了!!

看不懂的读者朋友们回去阅读我前面的文章~~

代码运行效果:

在这里插入图片描述

总结

Python中,不同的异常处理方法适用于不同的场景。

  • 使用 try-except 块适用于处理已知可能发生的错误,适用于具体函数或代码块中的错误处理。
  • sys.excepthook 适用于记录未捕获的异常,用于错误报告和日志记录,但不能阻止程序终止。
  • 装饰器适用于需要统一异常处理逻辑的函数,提高代码的复用性和清晰度。

在选择异常处理方法时,应根据具体需求和项目背景考虑使用哪种方法,并根据最佳实践和注意事项来编写异常处理代码,以确保代码的健壮性和可维护性。

后话

本次分享到此结束,

see you~🐱‍🏍🐱‍🏍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/134319.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot集成JWT,用户名,密码生成token

何为token&#xff1f;【如果想直接看代码可以往下翻】 使用基于 Token 的身份验证方法&#xff0c;在服务端不需要存储用户的登录记录。大概的流程是这样的&#xff1a; 1. 客户端使用用户名跟密码请求登录 2. 服务端收到请求&#xff0c;去验证用户名与密码 3. 验证成功后&a…

IOC - Google Guice

Google Guice是一个轻量级的依赖注入框架&#xff0c;专注于依赖注入和IoC&#xff0c;适用于中小型应用。 Spring Framework是一个全面的企业级框架&#xff0c;提供了广泛的功能&#xff0c;适用于大型企业应用。 是吧&#xff01;IOC 容器不止Spring,还有Google Guice,来体…

Linux的make和Makefile

目录 一、 介绍二、快速使用三、依赖关系和依赖方法四、语法 一、 介绍 1、makefile带来的好处就是——“自动化编译”&#xff0c;一旦写好&#xff0c;只需要一个make命令&#xff0c;整个工程完全自动编译&#xff0c;极大的提高了软件开发的效率。 2、make是一个命令工具&…

一文了解游戏行业(数据分析)

一.概况 1.基本术语 游戏行业基础术语——持续更新ing... 2.产业链 包括游戏开发&#xff0c;发行和销售等环节 游戏开发&#xff1a;上游环节&#xff1b;是游戏产业链的核心环节&#xff0c;包括游戏策划&#xff0c;美术设计&#xff0c;程序开发等&#xff0c;是决定游…

redux-devtools谷歌扩展插件的使用示例

目录 1. store.ts 2. reducer.ts 3. ReduxProvider.tsx 4. mapStateToProps.ts 5. mapDispatchToProps.ts 6. Todo组件(最外层包ReduxProvider 7. Todo组件里面涉及的子组件 1) TodoInput.tsx 2) TodoList.tsx 3) TodoItem.tsx 8. App组件使用Todo组件 1. store.ts …

组件的设计原则

目录 插槽的基本概念 基础用法 具名插槽 使用场景 布局控制 嵌套组件 组件的灵活性 高级用法 作用域插槽 总结 前言 Vue 的 slot 是一项强大的特性&#xff0c;用于组件化开发中。它允许父组件向子组件传递内容&#xff0c;使得组件更加灵活和可复用。通过 slot&…

【LeetCode】挑战100天 Day09(热题+面试经典150题)

【LeetCode】挑战100天 Day09&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-112.1 题目2.2 题解 三、面试经典 150 题-113.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…

索尼RSV文件怎么恢复为MP4视频

索尼相机RSV是什么文件&#xff1f; 如果您的相机是索尼SONY A7S3&#xff0c;A7M4&#xff0c;FX3&#xff0c;FX3&#xff0c;FX6&#xff0c;或FX9等&#xff0c;有时录像会产生一个RSV文件&#xff0c;而没有MP4视频文件。RSV其实是MP4的前期文件&#xff0c;经我对RSV文件…

进程线程

从Android3.0开始&#xff0c;系统要求网络访问必须在子线程中进行&#xff0c;否则会抛出异常&#xff0c;这么做是为了避免主线程被阻塞而导致ANR&#xff0c;那么网络访问的操作就必须要放到线程中去执行。 进程 进程是操作系统结构的基础&#xff0c;是程序在一个数据集合…

Day27力扣打卡

打卡记录 情侣牵手&#xff08;并查集&#xff09; 链接 class Solution:def minSwapsCouples(self, row: List[int]) -> int:def find(x: int) -> int:if p[x] ! x:p[x] find(p[x])return p[x]n len(row) >> 1p list(range(n))for i in range(0, len(row), 2…

Windows 11系统cmd终端美化、Vscode终端美化

win11美化cmd终端和vscode的终端 1. 修改终端背景2. oh-my-posh2.1 安装oh-my-posh2.2 安装Clink2.3 Clink配置oh-my-posh2.4 下载和配置Nerd字体2.5 修改美化主题 3. vscode终端美化 电脑默认的终端没有语法高亮这些&#xff0c;运行命令和代码输出字体一样&#xff0c;有时会…

计算机视觉中目标检测的数据预处理

本文涵盖了在解决计算机视觉中的目标检测问题时&#xff0c;对图像数据执行的预处理步骤。 首先&#xff0c;让我们从计算机视觉中为目标检测选择正确的数据开始。在选择计算机视觉中的目标检测最佳图像时&#xff0c;您需要选择那些在训练强大且准确的模型方面提供最大价值的图…

初识-Servlet (第一个 Servlet 程序详解)

Servlet 是什么? Servlet 是一种实现动态页面的技术. 是一组 Tomcat 提供给程序员的 API, 帮助程序员简单高效的开发一个 web app. 静态页面就只是单纯的 html 动态页面则是 html 数据 第一个 Servlet 程序 我们写一个 hello world 预期写一个 Servlet 程序, 部署到 Tomca…

WebRTC简介及使用

文章目录 前言一、WebRTC 简介1、webrtc 是什么2、webrtc 可以做什么3、数据传输需要些什么4、SDP 协议5、STUN6、TURN7、ICE 二、WebRTC 整体框架三、WebRTC 功能模块1、视频相关①、视频采集---video_capture②、视频编解码---video_coding③、视频加密---video_engine_encry…

【ElasticSearch】学习使用DSL和RestClient编写查询语句

文章目录 DSL和RestClient的学习前言1、DSL查询文档1.1 查询分类1.2 全文检索查询1.21 全文检索概述1.2.2 基本使用 1.3 精确查询1.3.1 term查询1.3.2 range查询 1.4 地理坐标查询1.4.1 geo_bounding_box查询1.4.2 geo_distance查询 1.5 复合查询1.5.1 常见相关性算法1.5.2 算分…

ArcGIS进阶:栅格计算器里的Con函数使用方法

本实验操作为水土保持功能重要性评价&#xff1a; 所用到的数据包括&#xff1a;土地利用类型数据&#xff08;矢量&#xff09;、植被覆盖度数据&#xff08;矢量&#xff09;和地形坡度数据&#xff08;栅格&#xff09;。 由于实验数据较少&#xff0c;其思路也较为简单&a…

讯飞录音笔误删除WAV录音文件恢复成功案例

讯飞录音笔删除恢复的难点 难点一&#xff0c;电脑无法识别为普通电脑盘符。这个是厂家系统设计上的问题&#xff0c;本博文不涉及。 难点二&#xff0c;一般恢复后播放有间隙性噪音问题。这个是数据碎片问题&#xff0c;是本博文的关注点。 大多数情况下&#xff0c;讯飞录…

钉钉统计部门个人请假次数go

前言 最近小组需要统计部门各种请假次数&#xff0c;写了一个方法&#xff0c;第一次实战中用到递归函数&#xff0c;简单记录一下。 效果展示 这些数据不需要返回json&#xff0c;这里这样是为了方便测试。可以通过这些数据完成其它的操作。 功能实现 钉钉服务端调试工具A…

【java进阶】集合的三种遍历(迭代器、增强for、Lambda)

目录 一、先谈集合&#xff1a; 二、单列集合的三种遍历方式 迭代器遍历 增强for遍历 Lambda表达式遍历 一、先谈集合&#xff1a; &#x1f525;那我们平常用for循环依赖下标遍历不行嘛&#xff0c;这就与集合的分类有关了。 集合的体系结构&#xff1a; collection是单…

【论文笔记】Denoising Diffusion Probabilistic Models

Pre Knowledge 1.条件概率的一般形式 P ( A , B ) P ( B ∣ A ) P ( A ) P(A,B)P(B|A)P(A) P(A,B)P(B∣A)P(A) P ( A , B , C ) P ( C ∣ B , A ) P ( B , A ) P ( C ∣ B , A ) P ( B ∣ A ) P ( A ) P(A,B,C)P(C|B,A)P(B,A)P(C|B,A)P(B|A)P(A) P(A,B,C)P(C∣B,A)P(B,A)P…