国庆节10月1日
--


Python异常的概念、异常处理语法、捕获多种异常、finally关键字、异常的传递

异常(也称为Bug)就是程序运行过程中出现的错误,它会中断程序的正常执行流程。
| 异常类型 | 说明 |
|---|---|
| NameError | 名称错误(变量或函数名不存在) |
| TypeError | 类型错误(类型不匹配) |
| IndexError | 索引错误(索引超出范围) |
| KeyError | 键错误(字典的键不存在) |
| ValueError | 值错误(值不合法) |
异常不是坏东西,而是编写健壮程序的重要工具
程序运行过程中出现异常,有两种处理方案:
1try:2 可能出现异常的业务代码13 可能出现异常的业务代码24 ...5except [异常类型 as 变量名]:6 出现异常时的预案7[finally:8 不管是否出现异常,都会执行的代码]1try:2 print("=" * 30)3 print(my_name)4 print("=" * 30)5except NameError as e:6 print("程序运行报错,错误信息:", e)7finally:8 print("释放资源 ~")1try:2 print("=" * 30)3 # print(my_name) # NameError4 # print(1 / 0) # ZeroDivisionError5 # print("ABC"[10]) # IndexError6 print("ABC".hello) # AttributeError7 print("=" * 30)8except NameError as e: # 捕获的是 NameError 类型的异常9 print("名字不存在,请检查变量或函数名字,异常信息:", e)10except ZeroDivisionError as e:11 print("0不能做被除数,异常信息:", e)12except IndexError as e:13 print("索引错误,异常信息:", e)14except Exception as e: # 捕获所有的异常15 print("程序运行出错了,请联系管理员,错误信息:", e)16finally: # 无论程序是否正常运行,finally代码块中的代码都会运行17 print("资源释放 ~")为什么要捕获异常?
如何捕获异常,具体的语法?
1try:2 print("ABC".hello)3except NameError as e:4 print("名称不存在,请检查,具体信息:", e)5except ZeroDivisionError as e:6 print("0不能做被除数,请检查,具体信息:", e)7except IndexError as e:8 print("索引错误,请检查,具体信息:", e)9except Exception as e:10 print("其他错误,请检查,具体信息:", e)11finally:12 print("无论正常执行还是出现异常,都要释放资源 ~")
finally是可有可无的
异常传递就是异常在函数调用中层层上报的过程,直到有人处理它,或者程序崩溃。
1def fun1():2 print("fun1 ... running ...")3 fun2()4
5def fun2():6 print("fun2 ... running ...")7 fun3()8
9def fun3():10 print("fun3 ... running ...")11 print(my_color) # 异常发生在这里12
13if __name__ == '__main__':14 fun1()1__main__ (fun1调用)2 ↓3fun1() (fun2调用)4 ↓5fun2() (fun3调用)6 ↓7fun3() (print(my_color) 报错)8 ↑9 │ 异常向上传递10 │11Exception被捕获或程序崩溃"ABC".hello)AttributeErrorexcept 异常类型 as 变量名:(变量名如 e)except Exception as e:,它要放在最后面finally 是可有可无的;无论程序正常执行(没出异常)还是出现异常,它里面的代码都会执行,常用来释放资源2-1 基础捕获 写一段代码:打印分隔线 → 打印一个不存在的变量 → 再打印分隔线。用捕获结构处理这个”名字不存在”的错误,打印”程序运行报错,错误信息:xxx”,并加上收尾块打印”释放资源 ~“。运行后观察:报错那行后面的分隔线有没有打印出来?
一级 · 思路:可能出错的代码放一个块,出错的预案放另一个块,收尾代码再放一个块
二级 · 方法:try / except 异常类型 as e / finally
三级 · 骨架:except ____ as e: / finally:(“名字不存在”的异常类型是 NameError)
1# 2-12try:3 print("=" * 30)4 print(my_name) # 变量不存在 → NameError5 print("=" * 30) # 这行不会执行(出错后直接跳到 except)6except NameError as e:7 print("程序运行报错,错误信息:", e)8finally:9 print("释放资源 ~")2-2 一份代码里捕获多种异常
一级 · 思路:一个 try 可以配多个 except,按异常类型从上往下匹配,匹配上就跳出去,不会回到出错的那一行继续
二级 · 方法:except IndexError as e / except KeyError as e / except ZeroDivisionError as e / except Exception as e
三级 · 骨架:except ____ as e: # 索引错误 / except ____ as e: # 兜底,放最后
1# 2-22try:3 print("=" * 30)4 print([1, 2, 3][10]) # 索引越界 → IndexError5 print({"a": 1}["b"]) # 键不存在 → KeyError6 print(1 / 0) # 除零 → ZeroDivisionError7 print("=" * 30)8except IndexError as e:9 print("索引错误,请检查下标是否越界,异常信息:", e)10except KeyError as e:11 print("键不存在,请检查字典的键,异常信息:", e)12except ZeroDivisionError as e:13 print("0 不能做除数,异常信息:", e)14except Exception as e:15 print("程序运行出错了,请联系管理员,错误信息:", e)16finally:17 print("资源释放 ~")18# 实际只会走到第一个出错的那行:先报 IndexError,剩下两行不会执行2-3 异常的传递
fun1() → 调用 fun2() → 调用 fun3(),每个函数进来先打印一行 xxx running ...fun3() 里访问一个不存在的变量,制造异常fun1(),运行并观察报错信息里显示的调用链顺序一级 · 思路:底层函数不处理,异常就沿着”谁调用了我”一层层往上报,谁接住谁负责
二级 · 方法:if __name__ == "__main__": 里写 try: fun1() + except NameError as e
三级 · 骨架:def fun3(): print(my_color) 制造异常;报错信息最后一行就是异常类型和说明
1# 2-32def fun1():3 print("fun1 ... running ...")4 fun2()5
6def fun2():7 print("fun2 ... running ...")8 fun3()9
10def fun3():11 print("fun3 ... running ...")12 print(my_color) # 异常发生在这里13
14if __name__ == "__main__":15 try:16 fun1()17 except NameError as e:18 print("在最外层捕获到异常:", e)19 finally:20 print("资源释放 ~")21# 不捕获时,报错信息里的调用链是:<module> → fun1 → fun2 → fun33-1 批量数据体检 把异常类型、多分支捕获、兜底和收尾块串成一个能用的小工具:
"88"、"92")、1 条不能转成数字的字符串(如 "abc")、1 条空字符串、1 个数字 0100 除以它,成功就打印算式和结果一级 · 思路:把 try 写在循环里面,一条数据出错只影响这一条;转整数和做除法分别会抛不同的异常
二级 · 方法:int(文本) 抛 ValueError;除以 0 抛 ZeroDivisionError;finally 放在 except 之后
三级 · 骨架:for item in raw_data: → try: → num = int(item) → result = 100 / num;except ____ as e: / except ____ as e: / finally: print("-" * 30)
1raw_data = ["88", "abc", "0", "", "92"]2
3success = 04for item in raw_data:5 try:6 num = int(item) # "abc"、"" 转不了 → ValueError7 result = 100 / num # 除数为 0 → ZeroDivisionError8 print(f"「{item}」通过:100 ÷ {num} = {result:.2f}")9 success += 110 except ValueError as e:11 print(f"「{item}」不能转成数字,跳过。异常信息:{e}")12 except ZeroDivisionError as e:13 print(f"「{item}」是 0,不能做除数,跳过。异常信息:{e}")14 except Exception as e:15 print(f"「{item}」出现其它错误,跳过。异常信息:{e}")16 finally:17 print("-" * 30) # 每条数据成功失败都会执行18
19print(f"处理完成,成功 {success} 条")20# 运行结果:88 和 92 通过,abc / 空字符串 / 0 各自被对应分支拦下,最后打印"成功 2 条"如果你喜欢,那么欢迎来到我的世界!
了解更多暂未播放



"生活不是等待暴风雨过去,而是学会在雨中跳舞。"—— 塞维涅夫人


