Python异常

2024-07-26 23:21:54 浏览数 (2)

前言

在Python中,异常是一种特定的对象,能够在程序运行过程中被抛出和处理。有效地管理异常不仅可以增强程序的稳定性,还可以提高用户体验,使程序能够优雅地处理错误情况。本章详细讲解了异常的基本概念、如何捕获和处理异常以及异常的传递性。


本篇文章参考:黑马程序员

一、什么是异常

当检测到一个错误时,Python解释器无法继续执行程序,反而会抛出错误提示,这就是我们所称的“异常”,也就是常说的“bug”。

bug这个单词是怎么诞生的呢?

"bug"这个词最初的确是指“虫子”。在英语中,"bug"可以用来描述各种小昆虫。早期计算机采用大量继电器工作,马克二型计算机出现了故障,技术人员尝试了多种方法,最后定位到第70号继电器出错。负责人哈珀仔细观察这个出错的继电器,发现一只飞蛾躺在中间,已经被继电器打死。她小心翼翼地用镊子将这只蛾子取出,将其用透明胶带粘贴在“事件记录本”上,并注明为“第一个发现虫子的实例”。自此之后,导致软件故障的缺陷便被称为“bug”。

代码语言:python代码运行次数:0复制
# 打开一个不存在的文件
f=open("D:/test.txt","r",encoding="UTF-8")

运行结果:

控制台打印出的错误信息通常表示在程序运行过程中遇到的异常(Exception)。当程序遇到无法处理的错误时,就会抛出异常,并在控制台输出相关的错误信息,包括异常类型、错误描述以及错误发生的位置。

二、捕获异常

为什么要捕获异常呢?

世界上没有完美的程序,任何程序在运行的过程中,都有可能出现异常,也就是出现bug,导致程序无法完美运行下去。

我们要做的,不是力求程序完美运行。而是在力所能及的范围内,对可能出现的bug,进行提前准备、提前处理。这种行为我们称之为异常处理(即捕获异常)。

当我们的程序遇到了Bug, 有以下两种情况:

  1. 整个程序因一个Bug停止运行。
  2. 程序能够提醒用户Bug的发生,并继续正常运行。

在实际工作中,我们肯定不能因为一个小小的Bug就让整个程序全部奔溃,所以我们希望的是达到第二种情况。为此,我们需要使用异常捕获技术。

捕获异常的作用:提前预测某个地方可能会出现异常,并做好相应的准备。当实际发生异常时,我们可以采取后续措施来处理这些异常。

①捕获常规异常

基本语法:

try:

  可能引发异常的代码

except:

  如果出现异常执行的代码

代码语言:python代码运行次数:0复制
# 捕获异常
try:
    # 打开一个不存在的文件
    f=open("D:/test.txt","r",encoding="UTF-8")
except:
    print("出现异常了,因为文件不存在,改为w模式打开")
    # w模式:当文件不存在时会创建一个文件
    f=open("D:/test.txt","w",encoding="UTF-8")

输出结果:

出现异常了,因为文件不存在,改为w模式打开

②捕获指定异常

基本语法:

try:

  可能引发异常的代码

except SpecificException as e:

  处理特定异常的代码

代码语言:python代码运行次数:0复制
# 捕获指定异常
try:
    print(name)
# 捕获 NameError 异常,并将异常对象赋值给变量 'e' 
except NameError as e:
    # 输出提示信息 
    print("出现变量未定义异常")
    # 输出异常对象 'e' 的信息
    print(e)

输出结果:

出现变量未定义异常

name 'name' is not defined

如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常。

代码语言:python代码运行次数:0复制
# 捕获指定异常
try:
    1/0
except NameError as e:
    print("出现变量未定义异常")
    print(e)

运行结果:

③捕获多个异常

当捕获多个异常时,将要捕获的异常类型的名字放到except 后,并使用元组的方式进行书写。

代码语言:python代码运行次数:0复制
# 捕获多个异常
try:
    1/0
except (NameError,ZeroDivisionError) as e:
    print("出现变量未定义或者除以0的异常")
    print(e)

输出结果:

出现变量未定义或者除以0的异常

division by zero

代码语言:python代码运行次数:0复制
# 捕获多个异常
try:
    print(name)
except (NameError,ZeroDivisionError) as e:
    print("出现变量未定义或者除以0的异常")
    print(e)

输出结果:

出现变量未定义或者除以0的异常

name 'name' is not defined

代码语言:python代码运行次数:0复制
# 捕获多个异常
try:
    print(name)
    1/0
except (NameError,ZeroDivisionError) as e:
    print("出现变量未定义或者除以0的异常")
    print(e)

输出结果:

出现变量未定义或者除以0的异常

name 'name' is not defined

仔细观察这个输出结果,为什么会输出name 'name' is not defined但是不会输出division by zero呢?

这是因为在Python中捕获多个异常时,try 块中的代码是自上而下执行的,一旦遇到异常,程序会立刻跳转到相应的 except 块,后续的代码将不再执行。

这段代码中,print(name) 这行会首先执行,然而 name 变量并不存在,所以会首先引发NameError异常并立即跳转到对应的 except 块来处理这个异常,而不会继续执行 try 块中的后续代码。因此,1/0 这行代码并不会执行,所以不会引发 ZeroDivisionError异常。

④捕获所有异常

基本语法1:

try:

  可能引发异常的代码

except:

  如果出现异常执行的代码

基本语法2:

try:

  可能引发异常的代码

except Exception as e:

  如果出现异常执行的代码

代码语言:python代码运行次数:0复制
# 捕获所有异常
# 写法一:(这种写法较为常用)
try:
    print(name)
except Exception as e:
    print("出现异常了")

# 写法二:
try:
    1/0
except:
    print("出现异常了")

输出结果:

出现异常了

出现异常了

⑤异常else

else表示的是如果没有异常要执行的代码。

代码语言:python代码运行次数:0复制
try:
    print("Hello")
except Exception as e:
    print("出现异常了")
else:
    print("没有出现异常")

输出结果:

Hello

没有出现异常

⑥异常finally

finally表示的是无论是否异常都要执行的代码。

代码语言:python代码运行次数:0复制
try:
    print("Hello")
except Exception as e:
    print("出现异常了")
else:
    print("没有出现异常")
finally:
    print("我是finally,有没有异常我都会执行")

输出结果:

Hello

没有出现异常

我是finally,有没有异常我都会执行

代码语言:python代码运行次数:0复制
try:
    1/0
except Exception as e:
    print("出现异常了")
else:
    print("没有出现异常")
finally:
    print("我是finally,有没有异常我都会执行")

输出结果:

出现异常了

我是finally,有没有异常我都会执行

三、异常的传递

异常是具有传递性的。

代码语言:python代码运行次数:0复制
# 定义一个出现异常的方法
def func1():
    print("func1 开始执行")
    num = 1 / 0     # 除以0的异常
    print("func1 结束执行")

# 定义一个无异常的方法,调用上面的方法
def func2():
    print("func2 开始执行")
    func1()
    print("func2 结束执行")

# 定义一个方法,调用上面的方法
def main():
    try:
        func2()
    except Exception as e:
        print(f"出现异常了,异常的信息是:{e}")

main()

输出结果:

func2 开始执行

func1 开始执行

出现异常了,异常的信息是:>division by zero

【分析】

当函数func01中发生异常, 并且没有捕获处理这个异常的时候, 异常会传递到函数func02,;当func02也没有捕获处理这个异常的时候,异常会传递到main函数;最终,main函数捕获了这个异常, 这就是异常的传递性。

注意:如果函数都没有捕获异常, 程序就会报错。

代码语言:python代码运行次数:0复制
# 定义一个出现异常的方法
def func1():
    print("func1 开始执行")
    num = 1 / 0     # 除以0的异常
    print("func1 结束执行")

# 定义一个无异常的方法,调用上面的方法
def func2():
    print("func2 开始执行")
    func1()
    print("func2 结束执行")

# 定义一个方法,调用上面的方法
def main():
    func2()
main()

运行结果:

利用异常具有传递性的特点,在main函数中设置异常捕获便可保证程序不会因为异常崩溃。因为整个程序无论在哪里发生异常,异常最终都会传递到main函数中,进而确保所有的异常都会被捕获。

0 人点赞