Skip to content

介绍 ​

  • 异常:就是程序运行过程中出现的错误,它会中断程序的正常执行流程。
  • 作用:
    • 保证数据、逻辑的正确性,避免程序执行混乱
    • 在开发阶段,尽量发现更多的问题,尽早解决问题,保障程序正常执行
python
total = 20000
num = input("请输入取款金额: ")

print(f"您的银行卡余额为: {total - int(num)}")
print("请取出您的银行卡, 欢迎您下次光临")

比如,在程序中,我们期望用户输入的取款金额是一个数字,如果用户输入数字,是没问题的,会将num字符串转为int类型。 但是如果用户输入的是 ABC 这样的非数字,那么此时转为int类型,程序就会报错,就会出现异常。【因此,这个异常是不是就是为了保证数据的正确性的】

异常的处理 ​

处理异常并不是让异常消失,而是需要将异常捕获到,然后根据捕获到的异常的情况,按照我们自己的处理方式,处理完异常,程序继续执行。(编写程序时,做好预案,出现异常后,按照预案处理)

python
try:
    可能出现异常的业务代码1
    可能出现异常的业务代码2
    ...
except [异常类型1 as 变量名]:
    出现异常1时的预案
except [异常类型2 as 变量名]:
    出现异常2时的预案
except [异常类型3 as 变量名]:
    出现异常3时的预案
except [异常类型4 as 变量名]:
    出现异常4时的预案
...

程序正常运行,except代码块中的代码不会运行。一旦程序运行出现错误,就会执行except中的异常处理逻辑,给用户提示出对应的错误信息。

可以使用多个except捕获多种不同类型的异常的。如果捕获了多种异常,程序运行出现异常后,会从上往下匹配,直到找到能处理该异常的except代码块,如果全部都匹配不到,异常就会直接抛出来,直接报错。

python
"""
- 异常:就是程序运行过程中出现的错误,它会中断程序的正常执行流程。
- 作用:
  - 保证数据、逻辑的正确性,避免程序执行混乱
  - 在开发阶段,尽量发现更多的问题,尽早解决问题,保障程序正常执行
- 处理方式:
    try:  #try中放可能出现异常的代码
        可能出现异常的业务代码1
        可能出现异常的业务代码2
        ...
    except [异常类型 as 变量名]:  # 处理异常的代码块,except可以有多个,分别处理不同类型的异常
        出现异常时的预案
    except [异常类型 as 变量名]:  # 处理异常的代码块,except可以有多个,分别处理不同类型的异常
        出现异常时的预案
- 快捷键:选中要放到try中的代码,ctrl+alt+t--->选择try/except
"""
try:
    a = int(input("请输入第一个数:"))
    b = int(input("请输入第二个数:"))
    sum = a+b
    c=a/b
    print(f"两个数之和:{sum}")
except ValueError as err:  # err是变量名,用来接收ValueError类型的异常,可以通过err变量获取异常的原因记录到文件中
    # print(err.args,type(err.args))  #err.args元组类型,存储异常原因,异常原因后期可以存到数据库、文件中,让开发人员查看
    print("请输入数字!")
except ZeroDivisionError as err:
    print("除数不能为0!")
# 当然,在实际的开发中,一般会直接选择except Exception这个方案捕获错误,因为其他的类型太具体了,有些错误我们是没办法提前知道具体的错误类型的
except Exception as err:
    print("程序开小差了,请稍后重试!")
finally:
    print("无论是否发生异常,都会执行的代码块")
print("程序执行结束了...")

如果 try 代码块中的代码运行出现异常,会从上往下匹配:先匹配ValueError类型,如果匹配上了,就执行except中的逻辑; 如果没有匹配上,继续往下匹配,匹配ZeroDivisionError ,如果匹配成功,就执行except中的逻辑;否则,会继续往下匹配。 而最后一个except,捕获的是Exception,这个是我们常见的这些错误的父类,如果前面的都没有匹配上,这个就会兜底。

异常传递 ​

异常传递就是异常在函数调用中层层上报的过程,直到有人处理它,或者程序崩溃。

python
def fun1():
    print("fun1开始")
    fun2()
    print("fun1结束")

def fun2():
    print("fun2开始")
    fun3()
    print("fun2结束")

def fun3():
    print("fun3开始")

    a = int(input("请输入第一个数:"))
    b = int(input("请输入第二个数:"))
    sum = a+b
    print(f"两个数之和:{sum}")

    print("fun3结束")

if __name__ == "__main__":
    try:
       fun1()   #快捷键:选中要放到try中的代码,ctrl+alt+t--->选择try/except
    except Exception as e:
        print("服务器正在升级,么么哒!")

程序运行时,调用的是fun1函数,fun1中调用了fun2,fun2中调用了fun3,如果fun3函数体的逻辑运行出现异常,异常未被捕获处理,则会顺着调用链路,一层一层的往上抛 (fun3 ---> fun2 ---> fun1 ---> 入口)。

案例优化 ​

学习了异常处理方案后,我们再来对我们的案例程序进行优化。由于 LibrarySystem 中的 run 方法是图书管理系统运行的入口,因此最简单的异常处理方案,就是在入口处,我们捕获所有的异常,然后给出用户提示就可以了 。(此处请参考面向对象部分的图书管理系统的代码)

python
# -------------------启动程序--------------------
if __name__ == "__main__":
    # ls = LibrarySystem()
    # ls.run()
    try:  #快捷键:选中要放到try中的代码,ctrl+alt+t--->选择try/except
        LibrarySystem().run()  # 创建LibrarySystem对象立马调用run()方法。由上面两行代码合并而来。
    except Exception as e:
        print(e.args)  #给开发人员看
        print("服务器正在升级,么么哒!")  #返回到页面,给用户看