該筆記是根據(jù)慕課網(wǎng)中相關(guān)視頻學(xué)習(xí)記錄。
視頻地址:https://www.imooc.com/learn/457
錯誤和異常的概念
概念
錯誤的概念
- 語法錯誤:代碼不符合解釋器或者編譯器語法
- 邏輯錯誤:不完整或者不合法輸入或者計算出先問題
異常的概念
- 程序遇到邏輯或者算法問題
- 運(yùn)行過程中計算機(jī)錯誤(內(nèi)存不夠或者IO錯誤)
區(qū)別
錯誤
- 代碼運(yùn)行前的語法或者邏輯錯誤
- 語法錯誤在執(zhí)行前修改
- 邏輯錯誤無法修改
異常
- 異常產(chǎn)生, 解釋器檢查到錯誤且認(rèn)為是異常,拋出異常
- 異常處理, 截獲異常,忽略或者種植程序處理異常
常見的錯誤
- 變量未賦值直接引用 錯誤信息為: NameError
- 語法錯誤: SyntaxError
- 打開不存在文件時 錯誤信息為:IOError
- 算術(shù)運(yùn)算除數(shù)為0時 錯誤信息為:ZeroDivision
- 強(qiáng)制類型轉(zhuǎn)換時元數(shù)據(jù)不符合轉(zhuǎn)換規(guī)則 錯誤信息為:ValueError
- 在IDE中使用 Ctrl+C 中斷程序執(zhí)行時 錯誤信息為:KeyboardInterupt
try-except 異常處理
代碼示例:
try:
print("測試代碼")
except Exception e:
print("異常處理代碼")
- try 用來捕獲 print("測試代碼") 中的異常,并且將異常就給except來處理
- except 用力啊處理異常,如果處理異常和設(shè)置捕獲異常 Exception 指向的一致,使用 print ("異常處理代碼") 來處理異常
try-except-else :處理多個異常
代碼示例
try:
f = open('1.txt', 'r')
# 讀取兩個字節(jié)的內(nèi)容
line = f.read(2)
num = int(line)
print("read the value is {}".format(num))
except IOError e:
print("catch IOError ", e)
except ValueError e:
print("catch ValueError ", e)
else:
print("it's fine, No Error")
- 上述例子中會有兩個 bug 一個是文件不存在,另一個是讀取的數(shù)據(jù)值(有字母)無法做 int() 強(qiáng)制轉(zhuǎn)換。
所以通過兩個except捕獲異常- else 的作用是對無異常時的操作,看情況添加
try-finally語句
代碼示例:
try:
f = open('1.txt', 'r')
res = int(f.read())
print(res)
finally:
print("file close")
f.close()
上述代碼執(zhí)行邏輯:
- 當(dāng) try 中的代碼塊執(zhí)行無異常時,正常執(zhí)行結(jié)束后,執(zhí)行 finally 中的代碼塊,打印信息和關(guān)閉文件。
- 當(dāng) try 中的代碼塊執(zhí)行有異常時,會先執(zhí)行finally中的內(nèi)容,打印信息和關(guān)閉文件,同時返回異常信息給python解釋器。
try-finally 執(zhí)行規(guī)則:
try-finally 無論是否會檢測到異常,都會執(zhí)行finally代碼。
try-finally 語句作用:
為異常處理事件提供 清理機(jī)制,用來關(guān)閉文件或者釋放系統(tǒng)資源。
try-except-finally
代碼示例:
try:
f = open('1.txt', 'r')
line = f.read(2)
num = int(line)
print("read num={}".format(num))
except IOError e:
print("catch IOError", e)
except ValueError e:
print("catch ValueError", e)
finally:
try:
print("close file")
f.close()
except NameError e:
print("catch NameError",e)
上述代碼執(zhí)行邏輯
try 中的代碼塊執(zhí)行打開文件,讀取文件中的2個字節(jié)信息,轉(zhuǎn)換為整型并打印出結(jié)果。
- 若沒有出現(xiàn)異常,執(zhí)行玩try代碼塊之后,執(zhí)行 finally 中的 try 代碼塊
- 當(dāng)出現(xiàn)異常時,先執(zhí)行異常的處理函數(shù),再執(zhí)行 finally 中的代碼塊,再 finally 中也有對異常的處理,主要是在,文件為被正常打開的情況下,關(guān)閉會出現(xiàn)異常,故會執(zhí)行 finally-except 中的內(nèi)容
try-except-finally 執(zhí)行規(guī)則
- 若 try 語句沒有捕獲異常,執(zhí)行完 try 代碼塊后,執(zhí)行 finally 。
- 若 try 語句捕獲到異常,首先執(zhí)行except處理錯誤,然后執(zhí)行 finally 。
try-except-else-finally語句
語法格式
try:
try_suite
except:
do_except
else:
do_else
finally:
do_finally
try-except-else-finally執(zhí)行規(guī)則
- 若 try 語句沒有捕獲異常,執(zhí)行完 try 代碼塊后,執(zhí)行 else 代碼段,最后執(zhí)行 finally
- 若 try 語句捕獲異常,首先執(zhí)行 except 處理錯誤,然后執(zhí)行 finally
with……as語句
語法格式
with context [as var]:
with_suite
- with 語句用來代替 try-except-finally語句,使代碼更加簡潔;
- context 表達(dá)式返回的是一個對象,該對象需要支持上下文協(xié)議
- var 用來保存 context 返回的對象,支持單個返回值為變量、多個返回值為元組類型
- with_suit 使用 var 變量來對 context 返回對象進(jìn)行操作
with 語句示例
with open("1.txt","r") as f:
for line in f.readlines():
print(line)
示例解釋
- open("1.txt","r") 打開文件的操作會生成一個臨時的對象
- with open("1.txt","r") as f 表示將剛剛生成的臨時對象賦值給變量 f
- with 中的代碼執(zhí)行(無異常)完成時,會 自動關(guān)閉文件,若 with 代碼塊有錯誤異常,則不關(guān)閉文件,被報錯中斷,故需要使用 try-except 捕捉異常。
- 對于上述的自動關(guān)閉功能可以使用 print(f.closed) 來驗(yàn)證,結(jié)果為 True 表示已關(guān)閉,F(xiàn)alse 表示未關(guān)閉
with 語句實(shí)質(zhì)是上下文管理
- 上下文管理協(xié)議: 包含方法 enter() 和 exit() , 支持該協(xié)議的對象要實(shí)現(xiàn)這兩個方法
- 上下文管理器: 定義執(zhí)行 with 語句時要在建立 運(yùn)行時上下文 ,負(fù)責(zé)執(zhí)行 with 語句塊上下文中的進(jìn)入退出操作
- 進(jìn)入上下文管理器: 調(diào)用管理器 enter()方法,如果設(shè)置 as var 語句,var 變量接受 enter() 方法 返回值
- 退出上下文管理器: 調(diào)用管理器 exit 方法,對資源進(jìn)行清理,對文件進(jìn)行關(guān)閉。
定義一個類學(xué)習(xí)上下文管理機(jī)制:
class Mycontext(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print("__enter__")
return self
def do_self(self):
print("do_self")
def __exit__(self, exc_type, exc_value, traceback):
# exc_type 參數(shù)表示 錯誤類型
# exc_value 參數(shù)表示 錯誤類型描述信息
# traceback 參數(shù)表示 出錯的堆棧信息,根據(jù)堆棧信息可以知道代碼是在哪一行出了錯誤
print("__exit__")
print("Error:", exc_type, "info:", exc_value)
if __name__ == '__main__':
with Mycontext("test_context") as f:
print(f.name)
f.do_self()
返回結(jié)果:
_enter_
test_context
do_self
_exit_
Error: None info: None
該執(zhí)行結(jié)果表明 with 語句會先執(zhí)行 _enter() 方法實(shí)例化一個對象,再 _init() 初始化對象, 再執(zhí)行相關(guān)操作,最后會執(zhí)行 _exit_() 操作,這是with語句規(guī)定的。
針對上述例子的異常捕獲
class Mycontext(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print("__enter__")
return self
def do_self(self):
print("do_self")
a
def __exit__(self, exc_type, exc_value, traceback):
# exc_type 參數(shù)表示 錯誤類型
# exc_value 參數(shù)表示 錯誤類型描述信息
# traceback 參數(shù)表示 出錯的堆棧信息,根據(jù)堆棧信息可以知道代碼是在哪一行出了錯誤
print("__exit__")
print("Error:", exc_type, "info:", exc_value)
if __name__ == '__main__':
with Mycontext("test_context") as f:
print(f.name)
f.do_self()
執(zhí)行結(jié)果
_enter_
test_context
do_self
_exit_
Error: <class 'NameError'> info: name 'a' is not defined
Traceback (most recent call last):
File "F:/脫產(chǎn)學(xué)習(xí)2017.10.27/兄弟連python/haolong/alice_code/demo/day7/test.py", line 27, in <module>
f.do_self()
File "F:/脫產(chǎn)學(xué)習(xí)2017.10.27/兄弟連python/haolong/alice_code/demo/day7/test.py", line 13, in do_self
a
NameError: name 'a' is not defined
該執(zhí)行結(jié)果表示代碼再執(zhí)行過程中出現(xiàn)在異常,會先執(zhí)行 _exit_()方法,再將異常拋出給python解釋器。
應(yīng)用場景
- 文件操作;
- 進(jìn)程線程之間互斥對象,例如互斥鎖;
- 支持上下文的其他對象
raise 語句和 assert 語句
raise 語句
raise 語句用于主動拋出異常
語法格式: raise [exception[,args]]
- exception: 異常類
- args: 描述異常信息的字符串
assert 語句
斷言語句:assert語句用于檢測表達(dá)式是否為真,如果為假,引發(fā) AssertionError 錯誤;
語法格式:assert expression[,args]
- expression: 表達(dá)式
- args:判斷條件的描述信息,字符串
應(yīng)用場景
定義函數(shù)或類中的方法,可以使用assert對傳入的參數(shù)進(jìn)行格式判斷。在通過 try-except 對異常進(jìn)行捕獲和處理
標(biāo)準(zhǔn)異常和自定義異常
標(biāo)準(zhǔn)異常:
標(biāo)準(zhǔn)異常:python 內(nèi)建異常,程序執(zhí)行前就已經(jīng)存在。

說明
- BaseException 類,所有異常都是繼承該類,若except中沒有指明異常的類型,則使用 BaseException 捕獲所有的異常
- KeyboardInterrupt 類是捕獲用戶使用 Ctrl + C 中斷程序?qū)е碌漠惓#苯永^承 BaseException 類
- Exception 類是系統(tǒng)、python解釋器異常的基類:
- 該類繼承于 BaseException 類
- 該類下還有 SyntaxError 類、NameError 類、IOError 類、 ImportError 類等多個子類
- SystemExit 類是當(dāng) python 解釋器退出時觸發(fā)這個類,出現(xiàn)異常
對于不明白的類,建議訪問 python 官網(wǎng),查看詳細(xì)信息
自定義異常:
- python 允許自定義異常,用于描述 python 中沒有涉及的異常情況。
- 自定義異常必須繼承 Exception 類或者Exception 類下的子類
- 自定義異常只能主動觸發(fā) raise方法觸發(fā)
自定義異常示例:
- 自定義異常:
class FileError(IOError): pass
- 產(chǎn)生自定義異常
raise FileError, "file Error"
- try-except 捕獲主動觸發(fā)的異常
try: raise FileError, "file Error" except FileError as e: print(e)