异常处理
我们知道,程序总会出现各种异常,出现异常,我们就应该去排查,去处理,使之良好地运行,程序的异常分为两类,一类是语法错误,这个比较低级,应该杜绝,各大IDE都有语法检测,写代码时出现飘红就应该想办法解决;另一类是逻辑错误,比如将一个字符串与整型相加,这种异常需要分情况加以处理
1. 利用if...else...分支解决
# 提示用户输入1~10的数字 num = input("输入选项:").strip() if num.isdigit(): num = int(num) if 1 <= num <= 10: pass else: print("请输入1~10的数字") else: print("请输入数字")
这种方式适用于分支少、层次简单的情况,如果分支很多或者有很多嵌套就会显得很臃肿,这时就需要第二种解决方式了
2. 利用try...except...捕获异常
在这之前我们先来看一下如果不用 if...else...分支会出现什么异常
num = input("输入选项:").strip() num = int(num) 输入选项:abc Traceback (most recent call last): File "D:/异常处理.py", line 32, in <module> num = int(num) ValueError: invalid literal for int() with base 10: 'abc'
从报错信息里可以看到出现了ValueError,因此我们可以通过捕获这个异常,然后根据这个异常进行某些操作
1 lst = ["大", "千", "世", "界"] 2 num = input("输入选项:").strip() 3 try: 4 num = int(num) 5 print(lst[num]) 6 except ValueError: # 输入的不是数字时,捕获这个异常 7 print("请输入数字") 8 except IndexError: # 输入的数字范围不对时,捕获这个异常 9 print("请输入0~3之间的数字")
上面的就是try...except...的多分支结构,单分支结构比它还简单,就是只有一个except分支,就不多介绍了
这里有一个小知识点:捕获异常的内容(不是名字)
1 lst = ["大", "千", "世", "界"] 2 num = input("输入选项:").strip() 3 try: 4 num = int(num) 5 print(lst[num]) 6 except ValueError as e: 7 print(e) # invalid literal for int() with base 10: 'abc' 8 except IndexError as e: 9 print(e) # list index out of range
当不知道会出现什么异常时,可以使用exception来表示所有异常
1 lst = ["大", "千", "世", "界"] 2 num = input("输入选项:").strip() 3 try: 4 num = int(num) 5 print(lst[num]) 6 except Exception as e: 7 print(e)
try...except...也可以嵌套,不过不建议使用
1 lst = ["大", "千", "世", "界"] 2 num = input("输入选项:").strip() 3 try: 4 num = int(num) 5 try: 6 print(lst[num]) 7 except IndexError: 8 print("请输入0~3的数字") 9 except ValueError: 10 print("请输入数字")
这里有一个小知识点:try...会在捕捉到第一个异常时就停止,然后执行except...的语句
lst = ["大", "千", "世", "界"] num = input("输入选项:").strip() try: print(111) num = int(num) print(222) except Exception as e: print(e) 输入选项:abc 111 invalid literal for int() with base 10: 'abc'
使用try...except...时,要根据具体情况选用合适的结构:
(1)当不关心异常信息,只是想跳过异常执行某些操作(退出等)时,使用try...except Exception...
(2)当需要根据异常的种类而执行不同的分支语句时,用try...except...的多分支结构较好
(3)大多数情况使用多分支加try...except Exception...
lst = ["大", "千", "世", "界"] dic = {1: "解", 2: "药"} num = input("输入选项:").strip() try: num = int(num) print(lst[num]) print(dic[num]) for k in dic: del dic[k] except IndexError as e: print(e) except KeyError as e: print(e) except Exception as e: print(e)
执行结果
输入选项:2
世
药
dictionary changed size during iteration
try...except...还可以与else连用,表示没有捕获到异常就执行else后面的语句
1 lst = ["大", "千", "世", "界"] 2 num = input("输入选项:").strip() 3 try: 4 num = int(num) 5 print(lst[num]) 6 except Exception as e: 7 print(e) 8 9 else: 10 print("一切都在掌握中...")
try...except...还可以与finally连用,表示有没有异常都执行finally后面的语句,这有什么用呢?做一些保存工作,比如关闭文件句柄、数据库连接等
# test.json {"1": "小王子", "2": "朝闻道"} import json try: f1 = open("test.json", encoding="utf-8", mode="r") dic = json.load(f1) print(dic["2"]) except KeyError as e: print(e) except Exception as e: print(e) finally: f1.close() print("in finally") try: f1.seek(0) # 移动光标到文件开头 data = f1.read() # 尝试读取文件内容,如果读取不到,就说明上面finally已经关闭了文件句柄 print(data) except Exception as e: print(e) # I/O operation on closed file.
try...finally...还可以在函数结束或者循环break之前执行一段语句
def func(): try: return 666 finally: print(111) func() # 111
def func(): try: while True: break finally: print(222) func() # 222
主动抛出异常
前面在类的约束里面已经用到过主动抛出异常,其语法为raise 异常名("异常内容")
raise ValueError("输入的值有误")
Traceback (most recent call last): File "D:/异常处理.py", line 241, in <module> raise ValueError("输入的值有误") ValueError: 输入的值有误
自定义异常
随着项目的扩展,有时会出现一些Python无法识别的异常,这时候就需要我们自己定义异常了
# PhoneConnectionError是提示的异常信息,但是直接写在except里解释器识别不了,所以需要自己先定义一个类 class PhoneConnectionError(BaseException): pass try: raise PhoneConnectionError("连接错误") except PhoneC
assert
用来让程序测试这个condition,如果condition为false,那么raise一个AssertionError出来。逻辑上等同于:
if not condition: raise AssertionError()
assert的一般用法是:assert condition [, arguments]
a = 1 b = 2 assert a == b, "a不等于b"
Traceback (most recent call last): File "D:/异常处理.py", line 262, in <module> assert a == b, "a不等于b" AssertionError: a不等于b