程序在運行過程中,難免會遇到錯誤,有的是編寫人員疏忽造成的語法錯誤,有的是程序內部隱含邏輯問題造成的數(shù)據(jù)錯誤,還有的是程序運行時與系統(tǒng)的規(guī)則沖突造成的系統(tǒng)錯誤,等等。如果出錯就不會執(zhí)行出錯語句后面的代碼,導致程序異常中斷,因此為了提高程序健壯性,容錯性,對容易發(fā)生錯誤的語句需要捕獲異常對異常處理,保證程序的連續(xù)性提高穩(wěn)定性。
def get_num(l:list, n1:int, n2:int):
print('執(zhí)行get_num函數(shù)')
num1 = l[n1]
num2 = l[n2]
res = num1/num2
return res
def func_1():
print('執(zhí)行func_1函數(shù)')
def func_2():
print('執(zhí)行func_2函數(shù)')
get_num([1,2,3,4],5)
func_1()
func_2()
上述代碼在調用函數(shù)get_num時會拋出indexError的異常,導致程序中斷?
def func_1():
x = 10
y = 0
b = x/y
print(b)
print("做完除法后需要執(zhí)行的代碼")
Traceback (most recent call last):
File "/Users/fujinjie/PythonProjects/develop_test/buyer_app_autotest/unit_test.py", line 30, in <module>
r = func_1()
File "/Users/fujinjie/PythonProjects/develop_test/buyer_app_autotest/unit_test.py", line 26, in func_1
b = x/y
ZeroDivisionError: division by zero
由于y = 0 ,即除數(shù)為0,程序拋出:ZeroDivisionError: division by zero 的異常,b = x/y后面的代碼并沒有被繼續(xù)執(zhí)行,因為出錯后程序是并不知道如何處理所以直接中斷后續(xù),并拋出錯誤告知用戶,假設在我們自動化測試中,可能要執(zhí)數(shù)百條用例,如果某一句子代碼執(zhí)行出現(xiàn)異常,則自動化程序就會異常中斷無法繼續(xù)執(zhí)行測試。
當一個程序發(fā)生異常時,代表該程序在執(zhí)行時出現(xiàn)了非正常的情況,無法再執(zhí)行下去。默認情況下,程序是要終止的。如果要避免程序退出,可以使用捕獲異常的方式獲取這個異常的名稱,再通過其他的邏輯代碼讓程序繼續(xù)運行,這種根據(jù)異常做出的邏輯處理叫作異常處理。異常處理不僅僅能夠管理正常的流程運行,還能夠在程序出錯時對程序進行必要的處理。大大提高了程序的健壯性和人機交互的友好性。
一、try...except...異常處理機制
def func_1():
x = 10
y = 0
try:
b = x/y
print(b)
except: # except捕獲所有類型的異常,即只要有異常就捕獲,不區(qū)分異常類型
print("出現(xiàn)錯誤異常后,執(zhí)行這里")
print("做完除法后需要執(zhí)行的代碼")
#出現(xiàn)錯誤異常后,執(zhí)行這里
做完除法后需要執(zhí)行的代碼
上面是通過try...except 優(yōu)化后的函數(shù),把會出錯的代碼放入try: 語句下作為try的子句,當try下面的代碼出錯時,程序會執(zhí)行except:下面的代碼,并執(zhí)行程序后續(xù)代碼,如果try: 下面的代碼沒有出錯,則跳過except: 直接執(zhí)行后續(xù)代碼,程序繼續(xù)運行。
在這里通過except我們捕獲try代碼塊中的錯誤和異常,相當于告訴程序,當try下面語句出錯時,該如何處理,上面我們直接做了一個字符串的輸出: "出現(xiàn)錯誤異常后,執(zhí)行這里"
二、except + 異常類型 捕獲指定類型的異常
def func_1():
x = 10
y = 0
try:
b = x/y
print(b)
except ZeroDivisionError as e: # as 為別名,當一個變量名稱太長時可取別名代替簡化
print(f"出錯啦,錯誤信息:{e}")
print("做完除法后需要執(zhí)行的代碼")
出錯啦,錯誤信息:division by zero
做完除法后需要執(zhí)行的代碼
基本語法構成
try:
可能產生異常的代碼塊
except [ (Error1, Error2, ... ) [as e] ]:
處理異常的代碼塊1
except [ (Error3, Error4, ... ) [as e] ]:
處理異常的代碼塊2
except [Exception]:
處理其它異常
該格式中,[] 括起來的部分可以使用,也可以省略。其中各部分的含義如下:
- (Error1, Error2,...) 、(Error3, Error4,...):其中,Error1、Error2、Error3 和 Error4 都是具體的異常類型。顯然,一個 except 塊可以同時處理多種異常。
- [as e]:作為可選參數(shù),表示給異常類型起一個別名 e,這樣做的好處是方便在 except 塊中調用異常類型(后續(xù)會用到)。
- [Exception]:作為可選參數(shù),可以代指程序可能發(fā)生的所有異常情況,其通常用在最后一個 except 塊。
try except 語句的執(zhí)行流程如下:
-
首先執(zhí)行 try 中的代碼塊,如果執(zhí)行過程中出現(xiàn)異常,系統(tǒng)會自動生成一個異常類型,并將該異常提交給 Python 解釋器,此過程稱為。
捕獲異常
-
當 Python 解釋器收到異常對象時,會尋找能處理該異常對象的 except 塊,如果找到合適的 except 塊,則把該異常對象交給該 except 塊處理,這個過程被稱為處理異常。如果 Python 解釋器找不到處理異常的 except 塊,則程序運行終止,Python 解釋器也將退出。
很多時間我們并不知道try下面包裹的子句會出現(xiàn)何種類型的異常,對于這種情況我們一般交給 Exception來處理,即表示可以接收任何類型的異常
?文章來源地址http://www.zghlxwxcb.cn/news/detail-815272.html
try:
#...
except Exception:
#...
一個簡的例子
try:
num_1 = int(input("輸入一個整數(shù):"))
num_2 = int(input("輸入另一個整數(shù):"))
print( num_1/num_2 )
except ValueError:
print("數(shù)值錯誤:程序只能接收整數(shù)參數(shù)")
except ArithmeticError:
print("算術錯誤")
except Exception:
print("未知異常")
該程序中,根據(jù)用戶輸入num_1 和 num_2 值的不同,可能會導致 ValueError、ArithmeticError 異常:
- 如果用戶輸入的 num_1 或者 num_2 是其他字符,而不是數(shù)字,會發(fā)生 ValueError 異常,try 塊會捕獲到該類型異常,同時 Python 解釋器會調用第一個 except 塊處理異常;
- 如果用戶輸入的 num_1 和 num_2 是數(shù)字,但 num_2 的值為 0,由于在進行除法運算時除數(shù)不能為 0,因此會發(fā)生 ArithmeticError 異常,try 塊會捕獲該異常,同時 Python 解釋器會調用第二個 except 塊處理異常;
- 當然,程序運行過程中,還可能由于其他因素出現(xiàn)異常,try 塊都可以捕獲,同時 Python 會調用最后一個 except 塊來處理。
通過traceback.format_exc()返回異常棧(返回是數(shù)據(jù)類型是字符串)
?文章來源:http://www.zghlxwxcb.cn/news/detail-815272.html
import traceback
def func_1():
x = 10
y = 0
try:
b = x/y
print(b)
except ZeroDivisionError as e: # as 為別名,當一個變量名稱太長時可取別名代替簡化
ei = traceback.format_exc()
print(f"出錯啦,錯誤信息:{e},{ei}")
print("做完除法后需要執(zhí)行的代碼")
出錯啦,錯誤信息:division by zero,Traceback (most recent call last):
File "C:\Users\37210\Desktop\Jcmall_study\test_b\b_3.py", line 8, in func_1
b = x/y
ZeroDivisionError: division by zero
做完除法后需要執(zhí)行的代碼
?常見異常舉例
IOError 輸入/輸出異常;基本上是無法打開文件
TypeError 傳入對象類型與要求的不符合
AttributeError 無法訪問該對象,一般對象不存在,比如foo.x,但是foo沒有屬性x
ImportError? 無法引入模塊或包;基本上是路徑問題或名稱錯誤
IndentationError? 語法錯誤(的子類) ;代碼沒有正確對齊
IndexError? 下標索引超出序列邊界,比如當x只有三個元素,卻試圖訪問x[5]
KeyError? 試圖訪問字典里不存在的鍵
NameError? 使用一個還未被賦予對象的變量
SyntaxError Python代碼非法,一般是語法錯誤
except 后面可以指定捕獲的錯誤類型,錯誤類型指定后,如果try:下面的代碼拋出的錯誤類型非該指定的類型,則不會被捕獲,程序仍舊會異常終止;?
?
def func_1():
x = 10
y = 0
try:
b = x/y
print(b)
except ValueError as e: # 這里對ValueError的異常進行捕獲
print(f"出錯啦,錯誤信息:{e}")
print("做完除法后需要執(zhí)行的代碼")
Traceback (most recent call last):
File "/Users/fujinjie/PythonProjects/develop_test/buyer_app_autotest/unit_test.py", line 33, in <module>
r = func_1()
File "/Users/fujinjie/PythonProjects/develop_test/buyer_app_autotest/unit_test.py", line 27, in func_1
b = x/y
ZeroDivisionError: division by zero
三、except 捕獲多個指定的錯誤類型?
def func_1():
x = 10
y = 0
try:
b = x/y
print(b)
except (TypeError,ValueError,ZeroDivisionError) as e: # 這里對 ZeroDivisionError的異常進行捕獲
print(f"出錯啦,錯誤信息:{e}")
print("做完除法后需要執(zhí)行的代碼")
出錯啦,錯誤信息:division by zero
做完除法后需要執(zhí)行的代碼
def func_1():
x = 10
y = "0" # 此處y是一個str類型
try:
b = x/y
print(b)
except (TypeError,ValueError,ZeroDivisionError) as e: # 這里對 TypeError的異常進行捕獲
print(f"出錯啦,錯誤信息:{e}")
print("做完除法后需要執(zhí)行的代碼")
出錯啦,錯誤信息:unsupported operand type(s) for /: 'int' and 'str'
做完除法后需要執(zhí)行的代碼
四、try...except...finally
Python異常處理機制還提供了一個?finally?語句,通常用來為 try 塊中的程序做掃尾清理工作
注意:finally 只要求和 try 搭配使用,而至于該結構中是否包含 except ,對于 finally 不是必須的
finally 語句的功能是:無論 try 塊是否發(fā)生異常,最終都要進入 finally 語句,并執(zhí)行其中的代碼塊。
def func_1():
x = 10
y = 0
try:
b = x/y
print(b)
finally:
print("無論try中代碼是不出現(xiàn)異常,finally中代碼始終會被執(zhí)行")
print("繼續(xù)執(zhí)行模塊中其他代碼")
def func_2():
x = 10
y = 1
try:
b = x/y
print(b)
finally:
print("無論try中代碼是不出現(xiàn)異常,finally中代碼始終會被執(zhí)行")
print("繼續(xù)執(zhí)行模塊中其他代碼")
比較上面兩個函數(shù) func_1與func_2,func_1中的try代碼塊會出現(xiàn)異常,func_2中的try代碼塊未出現(xiàn)異常,但兩個函數(shù)的finally包裹的子句都得到了執(zhí)行
五、try...except...else
在原本的
try except
結構的基礎上,Python異常處理機制還提供了一個 else 塊,也就是原有 try except 語句的基礎上再添加一個 else 塊,即
try:
#...
except:
#...
else:
#...
使用 else 包裹的代碼,只有當 try 塊沒有捕獲到任何異常時,才會得到執(zhí)行;反之,如果 try 塊捕獲到異常,即便調用對應的 except 處理完異常,else 塊中的代碼也不會得到執(zhí)行。
注意:else 必須和 try except 搭配使用
?
try:
result = 20 / int(input('請輸入除數(shù):'))
print(result)
except ValueError:
print('必須輸入整數(shù)')
except ArithmeticError:
print('算術錯誤,除數(shù)不能為 0')
else:
print('沒有出現(xiàn)異常')
print("繼續(xù)執(zhí)行")
try: 下面的代碼未發(fā)生異常,則執(zhí)行else: 下面的代碼,如果發(fā)生異常則執(zhí)行except: 下面的代碼,因此esle: 代碼塊的執(zhí)行與否,取決于try: 是否報異常;?
def func_1():
x = 10
y = 1
try:
b = x/y
print(b)
except: # except捕獲所有類型的異常,即只要有異常就捕獲,不區(qū)分異常類型
print("出現(xiàn)錯誤異常后,執(zhí)行這里")
else:
print("沒有異常會執(zhí)行這里的代碼")
finally:
print("finally中代碼始終會被執(zhí)行")
print("做完除法后需要執(zhí)行的代碼")
總結一個
Python異常處理語法結構如下
try:
#業(yè)務實現(xiàn)代碼
except Exception1 as e:
#捕獲到Exception1異常后執(zhí)行此代碼
...
except Exception2 as e:
#捕獲到Exception2異常后執(zhí)行此代碼
...
#可以有多個 except
...
else:
#try中未出現(xiàn)異常是執(zhí)行此處代碼,有異常時不會執(zhí)行
finally :
#不管try中代碼是否出現(xiàn)異常,此處代碼始終會執(zhí)行
...
注:finally必須跟try連用,跟except與else無連用關系;else必須跟try...except...連用
即整個結構try是必須存在的
- 如果沒有 try 塊,則不能有后面的 except 塊、else 塊和 finally 塊。但是也不能只使用?try 塊,要么使用 try except 結構,要么使用 try finally 結構;
- except 塊、else 塊、finally 塊都是可選的,當然也可以同時出現(xiàn);
- 可以有多個 except 塊,多個 except 塊必須位于 try 塊之后,finally 塊必須位于所有的 except 塊之后。
- 要使用 else 塊,其前面必須包含 try 和 except。
異常處理執(zhí)行過程
?
練習:
1、下面代碼存在keyError異常,請通過try...except捕獲并處理該異常,當錯誤時print輸出“輸入的key不存在,請檢查key”
goods_inf = {'Id': 10001, 'goods': 'JBL小音響', 'price': 501}
def get_goods_inf(goods:dict, key:str):
res = goods[key]
return res
get_goods_inf(goods=goods_inf, key='id')
2、請優(yōu)化下面函數(shù),當除數(shù)為0時捕獲異常并告知用戶除數(shù)不能為0,當輸入的是非數(shù)字時捕獲異常并提示用戶輸入的是非數(shù)字字符?
def add_num():
num1 = int(input('請輸入被除數(shù):'))
num2 = int(input('請輸入除數(shù):'))
res = num1/num2
return res
?
3、基于add_num函數(shù),請通過try...except...else優(yōu)化,當未捕獲到異常是函數(shù)返回res,當捕獲到異常時函數(shù)一律返回”輸入錯誤,請檢查輸入并把這個異常類型打印出來“
4、基于add_num函數(shù),請通過finally進行優(yōu)化,函數(shù)始終會通過print輸出’add_num函數(shù)執(zhí)行完畢’
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
到了這里,關于Python基礎之異常處理的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!