当前位置:   article > 正文

Chapter 18 Python异常

Chapter 18 Python异常

欢迎大家订阅【Python从入门到精通】专栏,一起探索Python的无限可能!


前言

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


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

一、什么是异常

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

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

# 打开一个不存在的文件
f=open("D:/test.txt","r",encoding="UTF-8")
  • 1
  • 2

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

二、捕获异常

为什么要捕获异常呢?
世界上没有完美的程序,任何程序在运行的过程中,都有可能出现异常,也就是出现bug,导致程序无法完美运行下去。
我们要做的,不是力求程序完美运行。而是在力所能及的范围内,对可能出现的bug,进行提前准备、提前处理。这种行为我们称之为异常处理(即捕获异常)。

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

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

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

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

①捕获常规异常

基本语法:
try:
  可能引发异常的代码
except:
  如果出现异常执行的代码

# 捕获异常
try:
    # 打开一个不存在的文件
    f=open("D:/test.txt","r",encoding="UTF-8")
except:
    print("出现异常了,因为文件不存在,改为w模式打开")
    # w模式:当文件不存在时会创建一个文件
    f=open("D:/test.txt","w",encoding="UTF-8")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

②捕获指定异常

基本语法:
try:
  可能引发异常的代码
except SpecificException as e:
  处理特定异常的代码

# 捕获指定异常
try:
    print(name)
# 捕获 NameError 异常,并将异常对象赋值给变量 'e' 
except NameError as e:
    # 输出提示信息 
    print("出现变量未定义异常")
    # 输出异常对象 'e' 的信息
    print(e)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

输出结果:
出现变量未定义异常
name ‘name’ is not defined

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

# 捕获指定异常
try:
    1/0
except NameError as e:
    print("出现变量未定义异常")
    print(e)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

运行结果:
在这里插入图片描述

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

# 捕获多个异常
try:
    1/0
except (NameError,ZeroDivisionError) as e:
    print("出现变量未定义或者除以0的异常")
    print(e)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

输出结果:
出现变量未定义或者除以0的异常
division by zero

# 捕获多个异常
try:
    print(name)
except (NameError,ZeroDivisionError) as e:
    print("出现变量未定义或者除以0的异常")
    print(e)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

输出结果:
出现变量未定义或者除以0的异常
name ‘name’ is not defined

# 捕获多个异常
try:
    print(name)
    1/0
except (NameError,ZeroDivisionError) as e:
    print("出现变量未定义或者除以0的异常")
    print(e)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

输出结果:
出现变量未定义或者除以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:
  如果出现异常执行的代码

# 捕获所有异常
# 写法一:(这种写法较为常用)
try:
    print(name)
except Exception as e:
    print("出现异常了")

# 写法二:
try:
    1/0
except:
    print("出现异常了")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出结果:
出现异常了
出现异常了

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

try:
    print("Hello")
except Exception as e:
    print("出现异常了")
else:
    print("没有出现异常")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

输出结果:
Hello
没有出现异常

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

try:
    print("Hello")
except Exception as e:
    print("出现异常了")
else:
    print("没有出现异常")
finally:
    print("我是finally,有没有异常我都会执行")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出结果:
Hello
没有出现异常
我是finally,有没有异常我都会执行

try:
    1/0
except Exception as e:
    print("出现异常了")
else:
    print("没有出现异常")
finally:
    print("我是finally,有没有异常我都会执行")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出结果:

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

三、异常的传递

异常是具有传递性的。

# 定义一个出现异常的方法
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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

输出结果:
func2 开始执行
func1 开始执行
出现异常了,异常的信息是:division by zero

【分析】
当函数func01中发生异常, 并且没有捕获处理这个异常的时候, 异常会传递到函数func02,;当func02也没有捕获处理这个异常的时候,异常会传递到main函数;最终,main函数捕获了这个异常, 这就是异常的传递性。
在这里插入图片描述
注意:如果函数都没有捕获异常, 程序就会报错。

# 定义一个出现异常的方法
def func1():
    print("func1 开始执行")
    num = 1 / 0     # 除以0的异常
    print("func1 结束执行")

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

# 定义一个方法,调用上面的方法
def main():
    func2()
main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/898022
推荐阅读
相关标签
  

闽ICP备14008679号