如何在Python中捕获异常

news2024/11/25 1:07:45

1. 写在前面

本文主要介绍 Python 捕获异常的各种技术。首先,回顾 Python 的异常处理机制,然后深入研究并学习如何识别捕获的异常内容,以及忽略异常。

公众号: 滑翔的纸飞机

2. Python 异常处理机制

Python 代码在运行的过程中,偶尔将出现意料之内或之外的错误从而引发异常。例如,如果尝试读取不存在的文件,就会发生这种情况。因为意料到可能会发生此类异常,所以应该编写代码来处理异常。相反,当你的代码执行不合逻辑操作时,也会发生错误。该类错误应该被修复,而不是处理。

当你的 Python 程序遇到错误并引发异常时,代码很可能会崩溃,但在崩溃停止之前会在控制台输出错误,说明问题所在:

例如:

>>> 12/'3'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'int' and 'str'

该示例,试图用一个数字除以一个字符串。Python 不支持,因此会引发 TypeError 异常。然后它会显示一个错误堆栈,提醒除法运算符对字符串不起作用。

为了在发生错误时采取措施,需要编写代码来捕获和处理异常,从而实现异常处理。这样做总比代码崩溃、影响用户要友好的多。要处理异常,Python中需要使用 try 语句。监控代码是否出现异常,并在出现异常时采取相应措施。

使用 try ... except ... else ... finally块

try:正常情况下,程序计划执行的语句。
except:程序异常是执行的语句。
else:程序无异常即try段代码正常执行后会执行该语句。
finally:不管有没有异常,都会执行的语句。

try:
<语句>        #运行别的代码
except <名字>:
<语句>        #如果在try部份引发了'name'异常
except <名字>,<数据>:
<语句>        #如果引发了'name'异常,获得附加的数据
else:
<语句>        #如果没有异常发生
finally:
<语句>        #无论异常是否出发,都将执行
  • try 代码块包含你希望监控异常的代码。任何在其中引发的异常都将得到处理。
  • 接着是一个或多个 except 块。可以在这些块中定义异常发生时运行的代码。在代码中,任何异常都会触发相关 except。注意,如果多个 except,程序将只运行第一个符合的 except ,而忽略其余 except 。

要了解如何工作,需要编写一个代码块。其中包括两个except代码块,分别用于处理 ValueError 和 ZeroDivisionError 异常,以便在异常发生时进行处理:

"""
@Time:2023/9/24 16:31
@Author:'jpzhang.ht@gmail.com'
@Describe:
"""

try:
    first = float(input("What is your first number? "))
    second = float(input("What is your second number? "))
    print(f"{first} divided by {second} is {first / second}")
except ValueError:
    print("You must enter a number")
except ZeroDivisionError:
    print("You can't divide by zero")

这段代码示例,要求用户输入两个数字(除数、被除数),并打印输出结果,如果用户输入不是数字,或者 float() 函数尝试将输入转换为浮点数时,如果无法转换,都将会引发ValueError。如果输入的第二个数字是 0,则会出现 ZeroDivisionError。这里 print() 函数尝试除以 0 时,会出现零点整除错误。

What is your first number? 2
What is your second number? 3
2.0 divided by 3.0 is 0.6666666666666666

What is your first number? 2
What is your second number? '5'
You must enter a number

What is your first number? 2
What is your second number? 0
You can't divide by zero

异常处理完成后,程序会继续执行 try 语句以外的代码。在本例中,没有其他任何代码,因此程序直接结束。

【注意】:示例代码只能捕获 ZeroDivisionError 或 ValueError 异常。如果出现其他异常,则会像以前一样崩溃。你可以通过创建一个 except Exception 子句来捕获所有其他异常。然而,这种做法并不可取,因为你可能会捕获到你没有预料到的异常。最好明确地捕获异常,并自定义对异常的处理。

通过简单示例,了解Python 异常处理机制,接下去步入正题。了解更多处理异常方式;

3. Python 捕获异常常用技巧

3.1 如何捕获几种可能的 Python 异常,并执行共同的处理?

如果需要对捕获的不同异常执行不同的处理操作,那么在单独的异常子句(except)中捕获单个异常是个不错的选择。如果你发现在处理不同异常时执行了相同的操作,那么你可以在单个异常子句中处理多个异常,从而编写出更简单、更易读的代码。为此,可以在 except 语句中以元组的形式指定异常。

假设,现在需要在之前的代码中,能够在一行中同时处理两种异常(ValueError、ZeroDivisionError),重写代码如下:

try:
    first = float(input("What is your first number? "))
    second = float(input("What is your second number? "))
    print(f"{first} divided by {second} is {first / second}")
except (ValueError, ZeroDivisionError) as error:
    print("There was an error")

现在,无论捕获 ValueError 或 ZeroDivisionError 异常,都将使用相同的 except 子句来处理。当然,也可以为其他异常添加额外的 except 子句,添加方式一样。

进一步思考:虽然 except 以相同的方式安全地处理了这两个异常,但如果你想知道到底是哪个异常被触发了。显然当前的处理方式并不能做到,接下来将学习如何做到这一点。

3.2 如何识别哪个 Python 异常被捕获?

如果你比较熟悉面向对象编程概念,那么你应该知道类是一种模板,它定义了实例化对象的内容。当你的代码引发 Python 异常时,它实际上是从定义异常的类中实例化了一个对象。例如,当代码引发一个 ValueError 异常时,其实是实例化了一个 ValueError 类的实例。

虽然异常处理对面向对象编程知识要求不高,但需要了解,之所以存在不同的异常对象,是因为它们是从不同的类中实例化出来的。

现在如果我们要识别之前代码中捕获的各个异常,可以通过如下实现:

try:
    first = float(input("What is your first number? "))
    second = float(input("What is your second number? "))
    print(f"{first} divided by {second} is {first / second}")
except (ValueError, ZeroDivisionError) as error:
    print(f"A {type(error).__name__} has occurred.")

输出:
What is your first number? 2
What is your second number? 0
A ZeroDivisionError has occurred.

What is your first number? 2
What is your second number? '2'
A ValueError has occurred.

这里对异常处理做了一些改进,不仅可以捕获 ValueError 和 ZeroDivisionError 异常,同时也将捕获的异常对象赋值给一个名为 error 的变量,这样可以对其进行进一步分析;

type(): 查看异常对象类型信息;
.__name__ : 获取类名;

在看一个稍复杂点的例子:

from operator import mul, truediv

def calculate(operator, operand1, operand2):
    return operator(operand1, operand2)

try:
    first = float(input("What is your first number? "))
    second = float(input("What is your second number? "))
    operation = input("Enter either * or /: ")
    if operation == "*":
        answer = calculate(mul, first, second)
    elif operation == "/":
        answer = calculate(truediv, first, second)
    else:
        raise RuntimeError(f"'{operation}' is an unsupported operation")
except (RuntimeError, ValueError, ZeroDivisionError) as error:
    print(f"A {type(error).__name__} has occurred")
    match error:
        case RuntimeError():
            print(f"You have entered an invalid symbol: {error}")
        case ValueError():
            print(f"You have not entered a number: {error}")
        case ZeroDivisionError():
            print(f"You can't divide by zero: {error}")
else:
    print(f"{first} {operation} {second} = {answer}")

**代码说明:**通过 operator 模块包含的 mul() 和 truediv() 函数来执行乘/除运算。程序根据用户输入将函数和数字传递给 calculate() 函数,calculate() 函数调用传递给它的运算符模块函数,执行计算。现在只有输入两个数字以及 ‘/’ 或 ‘*’ 进行运算时,该函数才会起作用。

【提示】:calculate() 函数可以直接使用 '* '或 ‘/’ 操作符,不过使用 mul()/truediv() 函数可以简化代码,提高可扩展性。

如果用户输入了无效的运算符,代码将显式抛出 RuntimeError 异常。

except 块和之前一样,额外增加了 RuntimeError 异常的捕捉,在 except 块中,根据异常类型匹配打印不同的消息。

try 块没有异常,将执行 else 代码块,打印执行结果。

3.3 如何使用超类捕获 Python 多种异常?

不同异常是从不同的类中实例化出来的。这些类都属于 Python 异常类。所有 Python 异常都继承自一个名为 BaseException 的类,其中一个子类就是 Exception 类。它是本文中要学习的所有异常的超类。

Python 包含六十多种不同的异常。下图只说明了其中的几种,但它包含了本教程中要介绍的所有异常子类。事实上,这些都是你可能会遇到的一些常见异常:

在这里插入图片描述

如上图,Exception 是所有其他异常的超类。Exception 的子类继承了 Exception 包含的所有内容。继承主要是为了创建异常层次结构。例如:ArithmeticError 是 Exception 的子类。从代码来看,它们之间的差异可以忽略不计。再看 OSError 类的两个子类(PermissionError、FileNotFoundError)。由于 OSError 继承自 Exception,因此也是 Exception 的子类。

我们可以利用子类是其超类的变体这一事实来捕获不同的异常。如以下代码:

from os import strerror

try:
    with open("datafile.txt", mode="rt") as f:
        print(f.readlines())
except OSError as error:
    print(strerror(error.errno))

os 就是“operating system”的缩写,顾名思义, os 模块提供的就是各种 Python 程序与操作系统进行交互的接口。os.strerror() 方法用于获取与错误代码对应的错误消息。

如果名为 datafile.txt 文件存在,代码将打印该文件的内容。如果 datafile.txt 不存在,代码就会引发 FileNotFoundError。虽然只包含了一个 except 子句,看起来只能捕获 OSError,但处理程序也可以处理 FileNotFoundError,因为它实际上是一个 OSError 的子类。

如果要确定捕获的是 OSError 的哪个子类,可以使用 type(error).__name__ 来打印它的类名。然而,这对大多数用户来说也毫无意义。相反,你可以通过 .errno 属性来识别底层错误。这是操作系统生成的一个数字,提供了引发 OSError 异常的相关信息。数字本身没有意义,但其相关的错误信息会告诉你更多有关问题的信息。

例如这里,异常处理程序使用变量 error,该变量引用了 OSError 异常的子类。要查看相关的错误信息,可以将错误代码传入 os.strerror() 函数。当你打印函数的输出时,你就会知道到底哪里出错了:

本示例输出:

No such file or directory

也可以尝试以下场景,用于验证是否可以捕获 PermissionError 异常:

创建文件 datafile.txt,但确保没有访问它的权限。然后再次尝试重新运行代码,并验证代码是否识别并处理异常。

3.4 如何忽略多个 Python 异常?

【重点】contextlib.suppress()

通常,当代码遇到异常时,会想要处理它。但有时,可能需要忽略异常,以使代码正常工作。例如,从可能被其他用户锁定的文件中读取数据。

在 Python 中忽略异常的传统方法是捕获异常但不做任何处理:

try:
    with open("file.txt", mode="rt") as f:
        print(f.readlines())
except (FileNotFoundError, PermissionError):
    pass

如上示例,捕获 FileNotFoundError、PermissionError 异常后不做处理,没有任何输出且程序正常运行。但代码可读性差,程序虽然捕获异常但不做处理。

这里介绍另一种更简洁的处理方式:

要编写明确忽略异常的代码,Python 提供了一个上下文管理器。通过 contextlib 模块来实现。

from contextlib import suppress

with suppress(FileNotFoundError, PermissionError):
    with open("file.txt", mode="rt") as f:
        print(f.readlines())

通过创建上下文管理器来忽略异常。

3.5 使用异常组捕获多个 Python 异常

当使用时 try… except 时,它实际只能捕获 try 块中出现的第一个异常。如果触发多个异常,程序将在处理完第一个异常后结束。其余的异常永远不会被触发。可以通过以下代码进行验证。

exceptions = [ZeroDivisionError(), FileNotFoundError(), NameError()]
num_zd_errors = num_fnf_errors = num_name_errors = 0

try:
    for e in exceptions:
        raise e
except ZeroDivisionError:
    num_zd_errors += 1
except FileNotFoundError:
    num_fnf_errors += 1
except NameError:
    num_name_errors += 1
finally:
    print(f"ZeroDivisionError was raised {num_zd_errors} times.")
    print(f"FileNotFoundError was raised {num_fnf_errors} times.")
    print(f"NameError was raised {num_name_errors} times.")

定义包含三个异常对象的列表。异常统计计数置0。循环触发异常(当然这里并不严谨),可以看到输出:

ZeroDivisionError was raised 1 times.
FileNotFoundError was raised 0 times.
NameError was raised 0 times.

仅有一个异常被捕获处理;

但有时可能需要处理所有发生的异常。例如,在并发编程(程序同时执行多个任务)中就需要这样做。在有并发任务运行的情况下,每个任务都会引发自己的异常。从 Python 3.11 开始,支持 ExceptionGroup 对象和一个特殊子句(exceptions.except*),允许处理所有异常。

调整先前的代码,演示如何处理多个异常。使用特殊语法:except*

exceptions = [ZeroDivisionError(), FileNotFoundError(), NameError()]
num_zd_errors = num_fnf_errors = num_name_errors = 0

try:
    raise ExceptionGroup("Errors Occurred", exceptions)
except* ZeroDivisionError:
    num_zd_errors += 1
except* FileNotFoundError:
    num_fnf_errors += 1
except* NameError:
    num_name_errors += 1
finally:
    print(f"ZeroDivisionError was raised {num_zd_errors} times.")
    print(f"FileNotFoundError was raised {num_fnf_errors} times.")
    print(f"NameError was raised {num_name_errors} times.")

try 块触发一个异常对象,该对象实例化时,将包含列表内容,它会将所有异常传递给处理程序。同时为了确保处理程序可以处理所有异常,这里 except <异常> 语法替代为 except* <异常>,当触发异常时,except* 块将处理任何异常。未匹配的异常通过每个 except* 向下传递。

ZeroDivisionError was raised 1 times.
FileNotFoundError was raised 1 times.
NameError was raised 1 times.

从输出中可以看出,程序成功地处理了所有异常,并正确增加了所有三个变量值。

4. 最后

本文除了介绍Python异常,也分享了一些更微妙的功能。

感谢您花时间阅读文章
关注公众号不迷路:

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

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

相关文章

5-1.(OOP)初步分析MCV架构模式

组成&#xff1a;模型&#xff08;model&#xff09;、视图&#xff08;view&#xff09;、控制器&#xff08;controller&#xff09; view&#xff1a;界面、显示数据 model&#xff1a;数据管理、负责在数据库中存取数据以及数据合法性验证 controller&#xff1a;负责转…

uni-app:顶部标题栏的部分相关设置(标题更改, 加载效果)

一、标题更改 效果 方法一&#xff1a;在pages.json中进行修改 {"path": "pages/index/index","style": {"navigationBarTitleText": "自定义标题"} }, 方法二&#xff1a;在页面直接进行修改 onLoad() {// 设置页面的标…

Spring Boot 如何配置 CORS 支持

Spring Boot 如何配置 CORS 支持 跨域资源共享&#xff08;CORS&#xff09;是一种重要的网络安全策略&#xff0c;用于限制浏览器在不同域之间的HTTP请求。Spring Boot提供了简单而强大的方法来配置CORS支持&#xff0c;以确保您的应用程序能够与其他域的资源进行安全交互。本…

某高校的毕设

最近通过某个平台接的单子&#xff0c;最后Kali做的测试没有公开可以私聊给教程。 下面是规划与配置 1.vlan方面&#xff1a;推荐一个vlan下的所有主机为一个子网网段 连接电脑和http客户端的接口配置为access接口 交换机与交换机或路由器连接的接口配置为trunk接口---也可以…

电商项目高级篇-02 elasticsearch-下

电商项目高级篇-02 elasticsearch-下 4.2、QueryDSL返回指定字段 4.2、QueryDSL 返回指定字段 返回单个字段 GET bank/_search {"query": {"match_all": {}}, "sort": [{"balance": {"order": "desc"}}], &quo…

IoTDB 在国际数据库性能测试排行榜中位居第一?测试环境复现与流程详解第一弹!...

最近我们得知&#xff0c;Apache IoTDB 多项性能表现位居 benchANT 时序数据库排行榜&#xff08;Time Series: DevOps&#xff09;性能排行第一名&#xff01;&#xff08;榜单地址&#xff1a;https://benchANT.com/ranking/database-ranking&#xff09; benchANT 位于德国&…

计算机竞赛 深度学习卫星遥感图像检测与识别 -opencv python 目标检测

文章目录 0 前言1 课题背景2 实现效果3 Yolov5算法4 数据处理和训练5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **深度学习卫星遥感图像检测与识别 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐…

【Vue】动态树与数据表格分页查询实现

目录 一、动态树 1.1 准备工作 1.1.1 准备数据库 1.1.2 准备好后台服务接口&#xff0c;Moudel查询&#xff0c;和Book查询&#xff08;支持分页&#xff09; 1.1.3 修改mock.js测试环境 1.1.4 配置请求路径 1.2 构建导航菜单 1.2.1 通过接口获取数据 1.2.2 通过后台获…

【LFU缓存机制】+双哈希表解法+排序解法

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;排序解法方法二&#xff1a;双哈希表 知识回顾双向链表的操作 写在最后 Tag 【LFU缓存】【哈希表】【设计数据结构】【2023-09-25】 题目来源 460. LFU 缓存 题目解读 为 LFU 缓存算法设计并实现数据结构。 LRU 缓存…

k8s集群安装v1.20.9后-2-改造部署自己的服务k8sApp,增加istio

1.环境准备: K8s集群,已经实现了k8s-app小例子,可以正常访问。(已包含docker) 在此基础上对项目进行改进,实现istio流量切换。 2.安装部署istio 2.1 安装go 官网下载go和istio的安装包,上传到k8s集群虚拟机上(三个机器都安装) [root@node1 ~]# cd /root/Public/i…

CSS实现围绕按钮边框转圈的光线效果

CSS实现围绕按钮边框转圈的光线效果&#xff0c;可以自由改变按钮的光线渐变颜色和按钮边框颜色&#xff0c;背景色等。 效果图&#xff1a; 实现完整代码&#xff1a; <template><view class"btnBlock"><view class"btnBian"></vi…

MySQL MHA 高可用

目录 1 MySQL MHA 1.1 什么是 MHA 1.2 MHA 的组成 1.3 MHA 的特点 2 搭建 MySQL MHA 2.1 Master、Slave1、Slave2 节点上安装 mysql5.7 2.2 修改 Master、Slave1、Slave2 节点的主机名 2.3 修改 Master、Slave1、Slave2 节点的 Mysql主配置文件/etc/my.cnf 2.4 在 Mast…

现代架构设计:构建可伸缩、高性能的分布式系统

文章目录 第1节&#xff1a;引言第2节&#xff1a;架构设计的关键原则2.1 微服务架构2.2 异步通信2.3 数据分区和复制2.4 负载均衡 第3节&#xff1a;代码示例3.1 创建产品服务3.2 创建消息队列3.3 创建产品更新服务 第4节&#xff1a;性能优化和监控4.1 建立性能基准4.2 水平扩…

国内大语言模型的相对比较:ChatGLM2-6B、BAICHUAN2-7B、通义千问-6B、ChatGPT3.5

一、 前言 国产大模型有很多&#xff0c;比如文心一言、通义千问、星火、MOSS 和 ChatGLM 等等&#xff0c;但现在明确可以部署在本地并且开放 api 的只有 MOOS 和 ChatGLM。MOOS 由于需要的 GPU 显存过大&#xff08;不量化的情况下需要80GB&#xff0c;多轮对话还是会爆显存…

Spring整合RabbitMQ——生产者(利用配置类)

1.生产者配置步骤 2.引入依赖 3.编写配置 配置RabbitMQ的基本信息&#xff0c;用来创建连接工厂的 编写启动类 编写配置类 4. 编写测试类

C#(CSharp)入门教程

目录 C#的第一个程序 变量 折叠代码 变量类型和声明变量 获取变量类型所占内存空间&#xff08;sizeof&#xff09; 常量 转义字符 隐式转换 显示转换 异常捕获 运算符 算术运算符 布尔逻辑运算符 关系运算符 位运算符 其他运算符 字符串拼接 …

unity lua开发体系搭建

在前面的文章里面我们已经介绍了怎么样在unity里面配置lua的开发环境&#xff0c;我们可以通过C#代码装载lua的脚本并执行相应的处理&#xff0c;这次我们一步步搭建下lua的开发体系。 1.基于c#体系所有的类都继承MonoBehaviour在这里lua环境下我们也需要创建一个类似于这个类的…

Stm32_标准库_呼吸灯_按键控制

Stm32按键和输出差不多 PA1为LED供给正电&#xff0c;PB5放置按键&#xff0c;按键一端接PB5,另一端接负极 void Key_Init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //APB2总线连接着GPIOBGPIO_InitStructur.GPIO_Mode GPIO_Mode_IPU;GPIO_InitStructur.…

@vitejs/plugin-legacy 为你的 Vite 项目提供对旧版浏览器的支持

vitejs/plugin-legacy 是 Vite 生态系统中的一个插件&#xff0c;它的作用是为你的 Vite 项目提供对旧版浏览器的支持。 具体而言&#xff0c;该插件会根据你在项目配置中指定的目标浏览器列表&#xff08;通过 browserslist 字段&#xff09;&#xff0c;自动生成兼容旧版浏览…

FPGA 图像缩放 千兆网 UDP 网络视频传输,基于RTL8211 PHY实现,提供工程和QT上位机源码加技术支持

目录 1、前言版本更新说明免责声明 2、相关方案推荐UDP视频传输--无缩放FPGA图像缩放方案我这里已有的以太网方案 3、设计思路框架视频源选择ADV7611 解码芯片配置及采集动态彩条跨时钟FIFO图像缩放模块详解设计框图代码框图2种插值算法的整合与选择 UDP协议栈UDP视频数据组包U…