如何在Python中捕获异常

这篇具有很好参考价值的文章主要介绍了如何在Python中捕获异常。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

python捕获异常错误内容,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异常,也分享了一些更微妙的功能。文章来源地址https://www.toymoban.com/news/detail-813935.html

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

到了这里,关于如何在Python中捕获异常的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python笔记2(函数参数、面向对象、装饰器、高级函数、捕获异常、dir)

    Python笔记1(赋值、浅拷贝和深拷贝、字符串日期转换、argparse、sys、overwrite、eval、json.dumps/json.loads、os.system(cmd)、zfill、endswith、open) 参数定义 在python中定义函数的时候,函数名后面的括号里就是用来定义参数的,如果有多个参数的话,那么参数之间直接用逗号, 隔开。 定义

    2024年02月08日
    浏览(52)
  • [oeasy]python0139_尝试捕获异常_ try_except_traceback

    变量相加 整型数字变量可以相加 字符串变量也可以拼接 但是 字符串 和 整型数字 整型数字 和 字符串 不能相加 怎么办? 转格式 int(“1”) str(2) 可是 如果输入的苹果数量是 字符串\\\"abc\\\" int(“abc”)会发生什么??😱 先试试看 虽然我有了心理准备 但是 python 显然还没有准备好

    2023年04月25日
    浏览(42)
  • php捕获Fatal error错误与异常处理

    在php5的版本中,如果出现致命错误是无法被 try {} catch 捕获的,如下所示: 运行脚本,最终php报出一个Fatal error,并程序中止 有些时候,我们需要捕获这种错误,并做相应的处理。 那就需要用到 register_shutdown_function() 和 error_get_last() 来捕获错误 对于php7中的错误捕获,因为

    2024年02月19日
    浏览(59)
  • 使用Python的Requests和BeautifulSoup库来爬取新闻网站的新闻标题、发布时间、内容等信息,并将数据存储到数据库中

    BeautifulSoup是Python的一个HTML/XML解析库,用于从HTML或XML文件中提取数据。结合Python的requests库,可以实现网页爬取和数据提取。 以下是一个简单的使用BeautifulSoup和requests库实现爬虫的示例:   用requests库和BeautifulSoup4库,爬取校园新闻列表的时间、标题、链接、来源。

    2024年02月10日
    浏览(55)
  • windows 达梦数据库服务连接时提示:登录服务器失败,错误号6001,错误消息:网络通信异常 之数据库服务不存在的处理方式

    在windows客户端上连接部署在windows操作系统上的达梦数据库, 使用DM管理工具连接数据库    正确输入用户名与密码之后点击确定按钮之后出现: 登录服务器失败,错误号6001,错误消息:网络通信异常  现象 如下图所示:   在之前也发布了一篇关于此错误的博文: 达梦管

    2024年02月11日
    浏览(57)
  • Java 异常处理以及如何捕获和处理多个异常

    在Java中,我们使用异常处理程序组件try,catch和finally块来处理异常。 为了捕获和处理异常,我们将try...catch...finally代码块放置在可能产生异常的代码周围。finally块是可选的。 try...catch...finally的语法为: 可能会生成异常的代码放在try块中。 每个try块后面应紧跟着catch 或 fi

    2024年02月14日
    浏览(44)
  • 用Python程序如何捕获Ctrl+C终止信号?

    对于一些连续运行或者长时间运行的Python程序而言,如服务器的后端,或者是长时间运行的科学计算程序。 当我们涉及到一些中途退出的操作时,比如使用Ctrl+C来退出正在运行的程序。 这种场景的出现一般有两个可能性:一是程序出现了问题,需要终止程序来对其进行调整

    2024年04月24日
    浏览(33)
  • Python如何调用达梦数据库

    Python如何调用达梦数据库 dmPython 是 DM 提供的依据 Python DB API version 2.0 中 API 使用规定而开 发的数据库访问接口。dmPython 实现这些 API,使 Python 应用程序能够对 DM 数据库进 行访问。 dmPython 通过调用 DM DPI 接口完成 python 模块扩展。在其使用过程中,除 Python 标准库以外,还需

    2024年02月07日
    浏览(46)
  • Python中处理HTTP异常和错误的策略

    在Python中处理HTTP异常和错误是一项至关重要的任务,它关乎到应用程序的健壮性、用户体验以及数据的安全性。HTTP请求可能会遭遇多种异常和错误,如连接错误、超时、HTTP状态码错误等。为了有效地处理这些异常和错误,开发者需要采取一系列策略。 1. 使用try-except捕获异

    2024年02月22日
    浏览(39)
  • Python基础合集 练习21 (错误与异常处理语句)

    ‘’‘try: block1 except[ExceptionName]: block2 ‘’’ while True: try: num = int(input(\\\'请输入一个数: \\\')) result = 50 / num print(result) print(‘50/{0}={1}’.format(num, result)) exit() # 退出程序 except ZeroDivisionError: print(‘除数不能为0,请重新输入’) while True: try: num = int(input(\\\'请输入一个数: \\\')) result = 50 /

    2024年02月02日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包