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

news2024/11/18 4:28:54

在这里插入图片描述

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

前言

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

本文旨在深入浅出地介绍Python中的异常处理,从基本概念到高级应用,我们将一步步探索Python异常处理的世界,揭示那些你可能未曾了解的知识和技巧。

异常处理概览

在``Python3.12.0的官方文档中,对异常的解释如下:
官方文档:https://docs.python.org/zh-cn/3/tutorial/errors.html

执行时检测到的错误称为 异常

什么是异常?

Python 中,异常指的是程序执行过程中发生的错误或意外情况。它们可能由各种原因产生,例如无效的输入、错误的操作或其他外部因素。当 Python 检测到这些情况时,会引发(或抛出)一个异常。异常本质上是一个对象,属于 Exception 类或其子类。代表了程序中出现的错误或意外。如果这个异常没有得到适当的处理,程序将终止并显示错误信息。

异常处理的重要性

异常处理是编写健壮且可维护代码的关键。适当的异常处理可以预防许多错误和程序崩溃,提高程序的稳定性和用户体验。通过有效的异常处理,我们可以控制程序在遇到错误时的反应,比如记录错误信息、恢复程序状态或通过警报通知用户。

异常处理的基本结构

Python 中的异常处理主要依赖于 try-except 语句块。将可能引发异常的代码放在 try 块中,并在 except 块中定义异常发生时的处理逻辑。此外,finallyelse 子句提供了更多的控制选项,允许在发生或未发生异常时执行特定代码。


标准异常类型

Python中的所有异常都继承自 BaseException 类。最常见的异常基类是 ExceptionPython标准库定义了许多不同类型的异常(如 ValueError, TypeError, IndexError, KeyError 等),它们都继承自 Exception

除此之外,Python也允许我们定义自己的异常类型,以适应特定的业务逻辑需求。

贴一个在菜鸟教程上的关于Python标准异常类型的表格:

异常名称描述
BaseException所有异常的基类
SystemExit解释器请求退出
KeyboardInterrupt用户中断执行(通常是输入^C)
Exception常规错误的基类
StopIteration迭代器没有更多的值
GeneratorExit生成器(generator)发生异常来通知退出
StandardError所有的内建标准异常的基类
ArithmeticError所有数值计算错误的基类
FloatingPointError浮点计算错误
OverflowError数值运算超出最大限制
ZeroDivisionError除(或取模)零 (所有数据类型)
AssertionError断言语句失败
AttributeError对象没有这个属性
EOFError没有内建输入,到达EOF 标记
EnvironmentError操作系统错误的基类
IOError输入/输出操作失败
OSError操作系统错误
WindowsError系统调用失败
ImportError导入模块/对象失败
LookupError无效数据查询的基类
IndexError序列中没有此索引(index)
KeyError映射中没有这个键
MemoryError内存溢出错误(对于Python 解释器不是致命的)
NameError未声明/初始化对象 (没有属性)
UnboundLocalError访问未初始化的本地变量
ReferenceError弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError一般的运行时错误
NotImplementedError尚未实现的方法
SyntaxErrorPython 语法错误
IndentationError缩进错误
TabErrorTab 和空格混用
SystemError一般的解释器系统错误
TypeError对类型无效的操作
ValueError传入无效的参数
UnicodeErrorUnicode 相关的错误
UnicodeDecodeErrorUnicode 解码时的错误
UnicodeEncodeErrorUnicode 编码时错误
UnicodeTranslateErrorUnicode 转换时错误
Warning警告的基类
DeprecationWarning关于被弃用的特征的警告
FutureWarning关于构造将来语义会有改变的警告
OverflowWarning旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning关于特性将会被废弃的警告
RuntimeWarning可疑的运行时行为(runtime behavior)的警告
SyntaxWarning可疑的语法的警告
UserWarning用户代码生成的警告

异常基本信息 & 语法

Python提供了一套异常处理机制,允许程序在发生异常时优雅地处理。

下面的这些部分共同构成了Python中异常处理的基础,在对它们充分理解后,可以帮助我们写出更健壮和易于维护的代码哦。

基本语法

Python中,异常处理的基本结构包括 try, except, else, 和 finally 块。

基本结构

try:
    # 尝试执行的代码
except ExceptionType:
    # 当上述代码引发ExceptionType异常时执行的代码
else:
    # 如果没有异常发生执行的代码
finally:
    # 无论是否发生异常都会执行的代码
  • try 块中放置的是可能引发异常的代码。
  • except 块定义了当特定异常发生时的处理逻辑。
  • else 块中的代码仅在没有异常发生时执行。
  • finally 块中的代码无论是否发生异常都会执行,通常用于执行一些清理工作。

示例

try:
    result = 10 / 2
except ZeroDivisionError:
    print("发生了除以零的错误")
else:
    print("结果是", result)
finally:
    print("执行完毕,无论是否发生异常")

在这个示例中,如果 try 块中的代码成功执行(即没有发生异常),那么 else 块中的代码将被执行。无论是否发生异常,finally 块中的代码都会被执行,通常用于资源释放或清理工作。

通过这种结构,Python的异常处理不仅可以处理错误情况,还能在正常情况下执行特定代码,并且确保最终总能执行某些必要的清理操作。


引发异常 (raise)

我们可以使用 raise 语句手动引发异常。这通常在检测到某些条件下,继续执行程序会导致问题时使用。

def check_age(age):
    if age < 18:
        raise ValueError("年龄不足18岁")


捕获异常 (try-except)

使用 try-except 语句块可以捕获和处理异常,防止程序意外崩溃。

try:
    check_age(15)
except ValueError as error:
    print("捕获到异常:", error)


获取详细异常信息(sys.exc_info)

在处理异常时,有时仅知道发生了异常并不足够,我们可能还需要了解异常发生时的更多上下文信息。Python提供了 sys.exc_info() 函数,它可以在异常处理块内被调用,以获取正在处理的异常的详细信息。

当在一个 except 块中调用 sys.exc_info() 时,它会返回一个包含三个值的元组,分别是:

  1. 异常类型 (exc_type): 引发的异常的类型。
  2. 异常值 (exc_value): 异常实例本身,通常包含错误消息。
  3. 追踪回溯对象 (exc_traceback): 包含异常发生时调用堆栈的详细信息的对象。

这些信息对于调试问题和记录错误日志非常有用。

示例

  • 通过使用 sys.exc_info(),可以获取到有关当前异常的更详尽的信息。
import sys
import traceback

try:
    # 可能引发异常的代码
    1/ 0
except ZeroDivisionError:
    exc_type, exc_value, exc_traceback = sys.exc_info()
    print("异常类型:", exc_type)
    print("异常值:", exc_value)
    print("追踪回溯:")
    # 直接打印异常的追踪信息到标准输出
    traceback.print_tb(exc_traceback)

代码运行结果如下:

在这里插入图片描述


基础异常处理代码

在实际应用中,通常会将引发和捕获异常结合起来,以确保程序的健壮性和可维护性。

示例

import sys
import traceback

def check_age(age):
    if age < 18:
        raise ValueError("年龄不足18岁")

try:
    age = 15
    check_age(age)
except ValueError as error:
    exc_type, exc_value, exc_traceback = sys.exc_info()
    print("捕获到异常:", error)
    print("异常类型:", exc_type)
    print("异常信息:", exc_value)
    print("追踪回溯:")
    # 获取异常的追踪信息。返回的是追踪信息的字符串列表,每个字符串代表追踪信息中的一行
    print(''.join(traceback.format_tb(exc_traceback)))
finally:
    print("处理完毕")

在这个示例中,当 check_age 函数引发 ValueError 异常时,except 块不仅会打印出异常信息,还会通过 sys.exc_info() 获取并打印出异常的类型、具体信息以及追踪回溯。这样做可以帮助我们更准确地理解异常发生的上下文,对于调试和记录错误日志非常有用。

代码运行效果如下:

在这里插入图片描述


自定义异常 (Custom Exceptions)

应用场景

  • 特定业务逻辑:当标准异常无法准确描述特定业务逻辑错误时。

优势

  • 代码清晰度:使错误处理更直观,提高代码的可读性。
  • 错误分类:方便对特定类型的错误进行特殊处理。

基础示例:

class MyCustomError(Exception):
    """一个自定义的异常类,用于特定的错误情况。"""


def my_function(value):
    if not value:
        raise MyCustomError("值不能为空")


再来一个接近真实编程环境中的示例代码,

示例代码

class NegativeValueError(Exception):
    """当输入值为负数时引发的异常。"""

    def __init__(self, value):
        self.value = value
        self.message = "输入值不应为负数"
        super().__init__(self.message)


def check_positive(number):
    if number < 0:
        raise NegativeValueError(number)
    return number


try:
    result = check_positive(-10)
except NegativeValueError as e:
    print(f"错误:{e.message} - 输入值: {e.value}")

代码释义:

这段代码定义了一个名为 NegativeValueError 的自定义异常类,用于处理输入值为负数的错误情况:

  1. 自定义异常类 NegativeValueError
    • 继承自Python的基本Exception类。
    • 包含一个构造函数,接受一个value参数,并设置一个错误消息"输入值不应为负数"
    • 通过super().__init__(self.message)调用基类构造函数,将错误消息传递给基类。
  2. 函数 check_positive
    • 这个函数接受一个数字作为参数。
    • 如果数字小于零,函数将引发NegativeValueError异常,传递该数字作为参数。
    • 如果数字非负,函数正常返回该数字。
  3. 异常处理
    • 使用try-except块来捕获NegativeValueError异常。
    • 如果捕获到此异常,将打印出错误消息和导致异常的值。

代码运行效果:

在这里插入图片描述


异常链 (Exception Chaining)

应用场景

  • 复杂的错误处理:在一个复杂的程序中,处理异常时可能会引发另一个异常,异常链可以帮助追踪这一过程。
  • 调试和日志记录:当需要详细记录或调试一个异常的整个发生过程时,异常链提供了一种追踪原始异常源的方法。

优势

  • 保留异常上下文:允许开发人员看到异常的“历史”,从最初的异常到最终的异常。
  • 提高可调试性:通过保留异常链,开发者可以更容易地理解错误的根本原因,特别是在复杂的系统中。

基础语法:

  • 异常链是通过在raise语句中使用from关键字来实现的。
  • SomeException是尝试捕获的异常类型,NewException是想要引发的新异常类型。通过使用from e,将原始的异常信息附加到新的异常上,从而创建了一个异常链。
try:
    # 尝试执行某些可能引发异常的操作
except SomeException as e:
    # 处理这个异常
    raise NewException("An error occurred") from e


先来看官方文档的示例:

def func():
    raise ConnectionError


try:
    func()
except ConnectionError as exc:
    raise RuntimeError('Failed to open database') from exc

代码运行效果如下:

  • 上述异常是导致以下异常的直接原因(直接就明说了,第2行是导致第8行错误的直接原因)

在这里插入图片描述


进一步的,我使用一个真实的例子,以方便大家的理解。

import json
import sys
import traceback


class DatabaseConnectionError(Exception):
    """自定义数据库连接异常"""

    def __init__(self, message):
        super().__init__(message)


def save_to_database(data):
    # 假设的数据库保存操作
    # 这里我们故意抛出一个异常来模拟数据库连接错误
    raise DatabaseConnectionError("数据库连接失败")


def process_file(filename):
    try:
        with open(filename, 'r') as file:
            data = json.load(file)
            save_to_database(data)
    except FileNotFoundError as e:
        raise RuntimeError("文件未找到") from e
    except DatabaseConnectionError as e:
        raise RuntimeError("数据库操作失败") from e


if __name__ == '__main__':
    # 调用函数
    try:
        process_file("data.json")
    except RuntimeError as e:
        print(f"捕获到异常: {e}")
        print(f"原始异常: {e.__cause__}")
        exc_type, exc_value, exc_traceback = sys.exc_info()
        traceback_details = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback))
        print("\nTraceback details:\n", traceback_details)

代码释义:

  1. 自定义异常类:定义 DatabaseConnectionError,创建了一个异常类型,用于数据库连接错误。

  2. 异常封装:在 process_file 函数中,捕获了两种类型的异常(FileNotFoundErrorDatabaseConnectionError),并将它们封装成 RuntimeError,同时保留了原始异常的信息。这是通过 from e 语法实现的,它创建了一个异常链,保留了底层异常的上下文。

  3. 异常信息打印:在外层的 try-except 块中,不仅打印了捕获的 RuntimeError 的信息,还打印了原始异常(e.__cause__)的信息,这有助于理解异常发生的完整路径。

  4. 完整的调用栈信息:通过使用 sys.exc_info()traceback.format_exception,能够获取并打印出异常发生时的完整调用栈信息。这对于定位异常发生的具体位置非常有用。

代码运行效果如下:

  • 异常信息打印的非常清晰~
    在这里插入图片描述

最佳实践和常见错误

最佳实践

  1. 使用具体的异常:捕获特定异常,避免通用异常捕获,以提供更准确的错误处理和反馈。
  2. 避免空的异常处理:不留空的except块,即使是简单记录错误也好。
  3. 使用异常链:在处理异常时保留原始异常信息,有助于调试和理解错误源。
  4. 资源清理:使用finally块或with语句确保资源(如文件和网络连接)得到适当清理。
  5. 自定义异常:当标准异常不足以表达特定错误时,定义自定义异常,使代码更易理解和维护。
  6. 异常消息的清晰度:提供清晰、具体的异常消息,有助于快速定位问题。
  7. 避免过多的异常处理:避免不必要或过度的异常捕获,以防隐藏代码中的真正问题。

常见错误

  1. 捕获太宽泛的异常:避免使用过于广泛的异常捕获(如except Exception:),可能会掩盖其他错误。
  2. 重复的异常处理:避免在多层函数调用中重复处理相同的异常,以免导致代码冗余和混乱。
  3. 忽视异常:不使用空的except块或完全忽视异常,以免错过潜在的错误。
  4. 异常滥用:避免使用异常来控制正常的程序流程,这不是异常设计的初衷。

总结✨✨

本文全面地介绍了Python中异常处理的各个方面,从基础知识到高级应用,提供了深入理解和有效管理异常的方法。

Python的异常处理是一个强大且灵活的机制,允许我们以优雅和有效的方式处理错误和意外情况。

重要的是要理解异常处理的原则和目的,即在不正常或意外的情况下保护程序的稳定性和可预测性。通过遵循最佳实践并避免常见的错误,我们可以编写更健壮、更可读且易于维护的代码。

后话

本次分享到此结束,

see you~🐱‍🏍🐱‍🏍

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯小程序音视频 TRTC live-pusher 黑屏等各种问题

微信小程序进行音视频开发, 主要会用到live-player live-pusher,这两个媒体组件. 在开发的过程中,会遇到各种各样的问题,其中最直接的就是黑屏问题, 以下就这个问题进行整理. 文档: https://developers.weixin.qq.com/miniprogram/dev/component/live-player.html https://dev…

【CASS精品教程】cass3d加载点云(.ilas和.las)并处理应用

本文讲解cass11.0 3d中将las点云转为ilas加载并进行后续处理。(cass11.0下载与安装) 一、ilas点云格式介绍 点云ilas格式是现今数字化三维模型建模的--种普遍被使用的数据格式,也被称作点云、点集或聚集点。它把地球表面上的物体,比如森林、海洋、河流、山脉等自然物体,以…

AI通义灵码能够帮你写通达信选股公式么?

答案是否定的 先不说语法错误&#xff0c;注释错误&#xff0c;就说AI压根不理解炸板和涨停板&#xff1b; 算了&#xff0c;股票交易AI千万别来掺和&#xff0c;会死的很惨的。

Linux下的调试工具——GDB

GDB 1.什么是GDB GDB 是由 GNU 软件系统社区提供的调试工具&#xff0c;同 GCC 配套组成了一套完整的开发环境&#xff0c;GDB 是 Linux 和许多 类Unix系统的标准开发环境。 一般来说&#xff0c;GDB 主要能够提供以下四个方面的帮助&#xff1a; 启动程序&#xff0c;可以按…

改进YOLOv8:结合ICCV2023|动态蛇形卷积,构建不规则目标识别网络

🔥🔥🔥 提升多尺度、不规则目标检测,创新提升 🔥🔥🔥 🔥🔥🔥 捕捉图像特征和处理复杂图像特征 🔥🔥🔥 👉👉👉: 本专栏包含大量的新设计的创新想法,包含详细的代码和说明,具备有效的创新组合,可以有效应用到改进创新当中 👉👉👉: �…

什么是稳定扩散,它是如何工作的?

推荐基于稳定扩散(stable diffusion) AI 模型开发的自动纹理工具&#xff1a; DreamTexture.js自动纹理化开发包 - NSDT 稳定扩散是潜在扩散模型的一个版本。潜在空间用于获得数据的低维表示的好处。之后&#xff0c;使用扩散模型和添加和去除噪声的方法根据文本生成图像。在接…

《红蓝攻防对抗实战》十.内网穿透之利用DNS协议进行隧道穿透

一.利用DNS协议进行隧道穿透 1.环境配置2.Windows系统下进行DNS隧道穿透利用3.Linux系统下进行DNS隧道穿透利用 前文推荐&#xff1a; 《红蓝攻防对抗实战》一. 隧道穿透技术详解 《红蓝攻防对抗实战》二.内网探测协议出网之TCP/UDP协议探测出网 《红蓝攻防对抗实战》三.内网…

抖音小程序开发:打造高效餐饮团购平台的技术指南

在餐饮行业&#xff0c;通过抖音小程序开发一个高效的团购平台&#xff0c;可以为餐厅提供更广泛的曝光&#xff0c;增加销售机会。本文将从技术角度出发&#xff0c;为您提供一份详细的抖音小程序开发指南&#xff0c;助您打造一流的餐饮团购平台。 一、确定需求和功能 在开…

LeetCode | 234. 回文链表

LeetCode | 234. 回文链表 O链接 这里的解法是先找到中间结点然后再将中间节点后面的节点逆序一下然后再从头开始和从中间开始挨个比较如果中间开始的指针到走最后都相等&#xff0c;就返回true&#xff0c;否则返回false 代码如下&#xff1a; struct ListNode* reverseLis…

只会CRUD程序员朋友,你开始拥抱云计算技术了吗

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概6000多字&#xff0c;预计阅读时间长需要6分钟。本篇文章的理论性较强&#xff0c;是一篇质量分数较高的技术文章&#xff0c;建议收藏…

11. EPIC定时器

11. EPIC定时器 EPIT定时器简介EPIT定时器结构分析EPIT 定时器相关寄存器EPITx_CREPITx_SREPITx_LR 加载寄存器EPITx_CMPR 比较寄存器EPITx_CNR 计数寄存器 EPIT 配置步骤 例程代码编写bsp_epittimer.hbsp_epittimer.cmain.c EPIT定时器简介 EPIT定时器是增强的周期中断定时器…

jupyter notebook中markdown改变图像大小

文章目录 &#x1f56e;原始图像&#x1f56e;改变图像大小&#x1f56e;使图像靠左 在 jupyter notebook中&#xff0c;导入的图片过大&#xff0c;想要改变图像的大小 &#x1f56e;原始图像 &#x1f56e;改变图像大小 复制小括号里面的内容到src后面&#xff0c;满足<…

【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;提供各种算法和数据结构的题目&…

【自定义类型:结构体】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 1. 结构体类型的声明 1.1 结构体的概念 1.2 结构的声明 ​编辑 1.3 特殊的声明 1.4 结构的自引用 2. 结构体变量的创建和初始化 3. 结构成员访问操作符 4. 结构体内…

学习linux必不可少的【yum命令】!

&#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Linux》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有一…

【JavaEE初阶】 TCP滑动窗口与流量控制和拥塞控制

文章目录 &#x1f384;为什么出现滑动窗口&#x1f38b;滑动窗口丢包问题&#x1f6a9;情况一&#xff1a;数据包已经抵达&#xff0c;ACK被丢了。&#x1f6a9;情况二&#xff1a;数据包就直接丢了 &#x1f332;流量控制&#xff08;安全机制&#xff09;&#x1f333;拥塞控…

STM32F4X SDIO(九) 例程讲解-SD卡擦除、读写

STM32F4X SDIO &#xff08;九&#xff09; 例程讲解-SD卡擦除、读写 例程讲解-SD卡擦除、读写SD卡擦除CMD32:ERASE_WR_BLK_START命令发送命令响应 CMD33:ERASE_WR_BLK_END命令发送命令响应CMD38:ERASE命令响应 CMD13:SD_CMD_SEND_STATUS命令发送命令回应 SD卡读数据CMD16:SET_…

C++ 配合图形库实现画线效果

#include<stdio.h> #include <conio.h> #include<math.h> #include <graphics.h> // 引用图形库头文件 #define N 12 int List[N][N];void draw() {for (int i 0; i < N; i) {int x 200 * cos(2 * 3.14 * i / N);int y 200 * sin(2 * 3.1…

SwiftUI 如何保证 Text 中字符数量相等的字符串显示宽度一定相同?

0. 问题现象 在 SwiftUI 中我们往往需要将内容相似的字符串展列出来给用户比较,这些字符串内容各有不同但字符数量始终是相等的,我们希望它们的显示宽度始终保持一致: 如上图所示:即使是等宽字符组成的字符串在字符数量相等时它们的显示宽度仍然可能不一致。但演示中最底部…

抖音短视频账号矩阵系统、短视频矩阵源码+无人直播源码开发可打包

抖音短视频账号矩阵系统、短视频矩阵源码无人直播源码开发可打包 矩阵系统源码主要有三种框架&#xff1a;Spring、Struts和Hibernate。Spring框架是一个全栈式的Java应用程序开发框架&#xff0c;提供了IOC容器、AOP、事务管理等功能。Struts框架是一个MVC架构的Web应用程序框…