標籤:and key 回溯 obj 導致 HERE var 忽略 刪除
一. 什麼是異常
python用異常對象(expection object)來表示異常情況。遇到錯誤後,會引發異常。如果是異常對象並未被處理或捕獲,程式就會用所謂的回溯(Traceback,一種錯誤資訊)終止執行:
>>> 1/0Traceback (most recent call last): File "<pyshell#0>", line 1, in <module> 1/0ZeroDivisionError: division by zero
事實上,每個異常都是一些類(本例中是ZeroDivisionError)的執行個體,這些執行個體可以被引發,並且可以用很多種方法進行捕捉,使得程式可以捉住錯誤並對其進行處理,而不是讓整個程式失敗
二. 異常處理:try...except...(else)
以下例子中,讓使用者輸入一個合法的整數,但允許使用者中斷整個程式(使用ctrl+c 或作業系統提供的方法),使用者中斷的資訊會引發一個KeyboardInterrupt異常
while True: try: x = int(input("Please enter a number: ")) break except ValueError: print("Oops! That was no valid number. Try again!")
try語句按照如下方式工作:
首先,執行try子句(在關鍵字try和關鍵字except之間的語句)
如果沒有異常發生,忽略except子句,try語句執行後結束
如果在執行try子句過程中發生了異常,那麼try子句餘下的部分將被忽略。如果異常的類型和except之後的名稱相符,那麼對應的except子句將被執行。最後執行try語句之後的代碼
如果一個異常沒有與任何的except匹配,那麼這個異常將會傳遞給上層的try中
一個try語句可能包含多個except子句,分別來處理不同的特定的異常,最多隻有一個分支會被執行
try except語句還有一個可選的else子句,如果使用這個子句,那麼必須放在所有的except子句之後。這個子句在try子句沒有發生任何異常的時候執行
#Filename: try_except.py
try: text = input("Enter something --> ")except EOFError: print("Why did you do an EOF on me?")except KeyboardInterrupt: print("You cancelled the operation.")else: print("You entered {0}".format(text))
輸出
Enter something --> Press ctrl-dWhy did you do an EOF on me?Enter something --> Press ctrl-cWhy did you do an EOF on me?Enter something --> no exceptionsYou entered no exceptions
最後一個except子句可以忽略異常的名字,它將被當作萬用字元使用
import systry: f = open("myfile.txt") s = f.readline() i = int(s.strip())except OSError as err: print("OS error: {0}".format(err))except ValueError: print("Could not convert data to an integer.")except: print("Unexcepted error:", sys.exc_info()[0]) raise三. 拋出異常
可以使用raise拋出一個指定的異常。raise的參數是指定的要拋出的異常,它必須是一個異常的執行個體或異常的類(也就是Exception的子類)
#拋出了一個沒有任何錯誤資訊的異常>>> raise ExceptionTraceback (most recent call last): File "<pyshell#0>", line 1, in <module> raise ExceptionException#拋出了一個添加了錯誤資訊的異常>>> raise Exception("hyperdrive overload")Traceback (most recent call last): File "<pyshell#1>", line 1, in <module> raise Exception("hyperdrive overload")Exception: hyperdrive overload四. 異常後的清理 try...(except)...finally
finally子句可以用來在可能的異常後進行清理,它和try子句聯合使用:
x = Nonetry: x = 1/0finally: print("Cleaning up...") del x
上面的代碼中,finally子句肯定會被執行,不管try子句中是否發生異常(在try子句之前初始化x的原因是:如果不這樣做,由於ZeroDivisionError的存在,x就永遠不會被賦值。這樣就會導致在finally子句使用del刪除它的時候產生異常,而且這個異常是無法捕捉的)
運行這段代碼,在程式奔潰之前,對於變數x的清理就完成了:
clean up...Traceback (most recent call last): File "D:/python_workshop/python6/revise/try_except.py", line 16, in <module> x = 1/0ZeroDivisionError: division by zero
因為使用del語句刪除一個變數是非常不負責的清理手段,所以finally子句用於關閉檔案或者網路通訊端時會非常有用,還可以在同一條語句中組合使用try, except, else, finally
try: 1/0except NameError: print("Unknow variable")else: print("That went well!")finally: print("Cleaning up.")五. with語句
在try塊中獲得資源,隨後又在finally塊中釋放資源,這是一種常見的模式。也有一種with語句能夠以清晰的方式完成這樣的功能
with open能夠在結束的時候自動關閉檔案。在螢幕後面發生的事情就是with語句使用了一種協議,獲得了open語句返回的對象,就叫"thefile"好了
在啟動代碼之前,在後台總會調用 thefile.__enter__函數,在代碼結束後又會調用thefile.__exit__函數
with open("poem.txt") as f: for line in f: print(line, end="")
如果我們在poem.txt檔案內寫入python之禪(可通過import this查看),得到的結果是:
The Zen of Python, by Tim PetersBeautiful is better than ugly.Explicit is better than implicit.Simple is better than complex.Complex is better than complicated.Flat is better than nested.Sparse is better than dense.Readability counts.Special cases aren‘t special enough to break the rules.Although practicality beats purity.Errors should never pass silently.Unless explicitly silenced.In the face of ambiguity, refuse the temptation to guess.There should be one-- and preferably only one --obvious way to do it.Although that way may not be obvious at first unless you‘re Dutch.Now is better than never.Although never is often better than *right* now.If the implementation is hard to explain, it‘s a bad idea.If the implementation is easy to explain, it may be a good idea.Namespaces are one honking great idea -- let‘s do more of those!
參考文章:
《Python3 錯誤和異常》
《Python基礎教程(第2版 修訂版)》
《A Byte of Python3(中文版)》
python中的異常處理