做爲 Python 初學者,在剛學習 Python 編程時,常常會看到一些報錯信息,這些報錯信息就是咱們接下來要講的錯誤和異常。python
咱們在執行程序語句的時候,常常會看到命令行輸出報錯信息,例如:編程
>>> while True print('Hello world') File "<stdin>", line 1, in ? while True print('Hello world') ^SyntaxError: invalid syntax
這種報錯信息會阻止程序正常運行,也就是咱們要介紹的錯誤和異常。數據結構
咱們說的錯誤指的是Python的語法錯誤,例如:app
>>> if 1=1: print('always') File "<stdin>", line 1 if 1=1: print('always') ^SyntaxError: invalid syntax
上面例子中,在判斷相等的時候應該用''==',而不是用'=',執行的時候,語法解析器檢查到有錯誤,程序語句終止執行,並將錯誤的地方用上箭頭指出來。ide
語法錯誤很好解決,根據命令行提示的錯誤位置,檢查語法,改正便可。函數
在Python中,即便你的代碼沒有語法錯誤,也不能保證程序按照你的想法運行完畢,由於在程序執行過程當中也會有錯誤。程序運行期間檢測到的錯誤被稱爲異常,例如:學習
>>> '1' + 2Traceback (most recent call last): File "<stdin>", line 1, in ?TypeError: Can't convert 'int' object to str implicitly
大多數的異常都不會被程序處理,都以錯誤信息的形式顯示出來,如上例所示,提示信息告訴咱們int類型不能和str類型相加。spa
錯誤提示信息會告訴咱們異常發生的上下文,並以調用棧的形式顯示具體信息,提示信息的最後一行開頭會顯示錯誤類型名稱,上例中,錯誤類型爲'TypeError',表示類型異常。命令行
異常是一個事件,該事件會在程序執行過程當中發生,從而影響程序的正常執行。當 Python遇到沒法處理的程序時,就會引起一個異常。在 Python 中,異常是一個對象,用於表示一個錯誤,當 Python腳本發生異常時咱們須要捕獲和處理它,不然程序會終止執行。3d
Python 提供了 try/except語句用來捕獲和處理異常。try 語句用來檢測語句塊中是否有錯誤,except 語句則用來捕獲 try 語句中的異常,並進行處理,附加的 else 能夠在 try 語句沒有異常時執行。
下面以最簡單的 try...except...else 爲例:
try: statement(s) # 要檢測的語句塊except exception: deal_exception_code # 若是在 try 部份引起了 'exception' 異常except exception2, e: deal_exception2_code # 若是引起了 'exception2' 異常else: no_exception_happend_code #若是沒有異常發生
try 語句的執行邏輯以下:
首先,執行 try 子句 (try 和 except 關鍵字之間的(多行)語句)。
若是沒有異常發生,則跳過 except 子句 並完成 try 語句的執行。
若是在執行try 子句時發生了異常,則跳過該子句中剩下的部分。而後,若是異常的類型和 except 關鍵字後面的異常匹配,則執行 except 子句,而後繼續執行 try 語句以後的代碼。
若是發生的異常和 except 子句中指定的異常不匹配,則將其傳遞到外部的 try 語句中;若是沒有找處處理程序,則它是一個 未處理異常,執行將中止並顯示錯誤消息。
若是 try 語句執行時沒有發生異常,那麼將執行 else 語句後的語句(若是有 else 的話),而後控制流經過整個 try 語句。
若是發生的異常和 except 子句中的類是同一個類或者是它的基類,則異常和 except 子句中的類是兼容的(但反過來則不成立 --- 列出派生類的 except 子句與基類兼容)。
class BException(Exception): #繼承Exception基類 pass
class CException(BException): #繼承BException基類 pass
class DException(CException): #繼承CException基類 pass
for cls in [BException, CException, DException]: try: raise cls() #拋出異常 except DException: print("D") except CException: print("C") except BException: print("B")
#輸出BCD
請注意若是 except 子句被顛倒(把 except BException 放到第一個),它將打印 B,B,B --- 由於DException類繼承CException類,CException類繼承BException類,將 except BException 放到第一個能夠匹配這三個異常,後面的 except 就不會執行。
Python能夠在全部 except 的最後加上 except 子句,這個子句能夠省略異常名,以用做通配符。它能夠捕獲前面任何 except (若是有的話)沒有捕獲的全部異常。
try: statement(s) # 要檢測的語句塊except exception: deal_exception_code # 若是在 try 部份引起了 'exception' 異常except : deal_all_other_exception2_code # 處理所有其它異常else: no_exception_happend_code #若是沒有異常發生
try: raise BException() #拋出異常except DException: print("D")except: print("處理所有其它異常") #處理所有其它異常
#輸出處理所有其它異常
一個 try 語句可能有多個 except 子句,以指定不一樣異常的處理程序,最多會執行一個處理程序。處理程序只處理相應的 try 子句中發生的異常,而不處理同一 try 語句內其餘處理程序中的異常。一個 except 子句能夠將多個異常命名爲帶括號的元組。
try: statement(s) # 要檢測的語句塊except exception: deal_exception_code # 若是在 try 部份引起了 'exception' 異常except (Exception1[, Exception2[,...ExceptionN]]]) : deal_all_other_exception2_code # 處理多個異常else: no_exception_happend_code #若是沒有異常發生
try: raise BException() #拋出異常except (BException, DException): print("D")except: print("處理所有其它異常") #處理所有其它異常else: print("沒有異常發生") #沒有異常發生
#輸出D
finally 語句用於不管是否發生異常都將執行最後的代碼。
try: # <語句>finally: # <語句> #退出try時總會執行
try: raise BException() #拋出異常except (BException, DException): print("D")except: print("處理所有其它異常") #處理所有其它異常else: print("沒有異常發生") #沒有異常發生finally: print("大家繞不過我,必須執行") #必須執行的代碼 #輸出D大家繞不過我,必須執行
這裏注意 finally 和 else 的區別,finally 是不管是否有異常都會執行,而 else 語句只有沒有異常時纔會執行。也就是說若是沒有異常,那麼 finally 和 else 都會執行。
except 子句能夠在異常名稱後面指定一個變量。這個變量和一個異常實例綁定,它的參數是一個元組,一般包含錯誤字符串,錯誤數字,錯誤位置,存儲在 .args 中。爲了方便起見,異常實例定義了__str__() ,所以能夠直接打印參數而無需引用 .args。
try: # 正常的操做 ......except ExceptionType as inst: # 能夠在這輸出 inst 的值.....
try: x = 1 / 0 # 除數爲0except ZeroDivisionError as err: #爲異常指定變量err print("Exception") print(err.args) #打印異常的參數元組 print(err) #打印參數,由於定義了__str__()
#輸出Exception('division by zero',)division by zero
Python 提供了 raise 語句用於手動引起一個異常。
raise [Exception [, args [, traceback]]]
Exception:異常的類型,例如 ZeroDivisionErrorargs:異常參數值,可選,默認值 "None"traceback:可選,用於設置是否跟蹤異常對象
異常參數值能夠是一個字符串,類或對象
def diyException(level): if level > 0: raise Exception("raise exception", level) #主動拋出一個異常,而且帶有參數 print('我是不會執行的') #這行代碼不會執行
try: diyException(2) #執行異常方法except Exception as err: #捕獲異常 print(err) #打印異常參數#輸出('raise exception', 2)
爲了可以捕獲異常,"except"語句必須有用相同的異常來拋出類對象或者字符串。若是要捕獲上面代碼拋出的異常,except 語句應該以下所示:
#定義函數def diyException(level): if level > 0: raise Exception("error level", level) #主動拋出一個異常,而且帶有參數 print('我是不會執行的') #這行代碼不會執行
try: diyException(2) #執行異常方法except 'error level' as err: #捕獲異常 print(err) #打印異常參數
#輸出Traceback (most recent call last): File "/Users/cxhuan/Documents/python_workspace/stock/test.py", line 51, in <module> diyException(2) #執行異常方法 File "/Users/cxhuan/Documents/python_workspace/stock/test.py", line 47, in diyException raise Exception("error level", level) #主動拋出一個異常,而且帶有參數Exception: ('error level', 2)
固然,咱們也能夠經過 traceback 來捕獲異常:
import traceback
#定義函數def diyException(level): if level > 0: raise Exception("error level", level) #主動拋出一個異常,而且帶有參數 print('我是不會執行的') #這行代碼不會執行
try: diyException(2) #執行異常方法except Exception: #捕獲異常 traceback.print_exc()#輸出Traceback (most recent call last): File "/Users/cxhuan/Documents/python_workspace/stock/test.py", line 51, in <module> diyException(2) #執行異常方法 File "/Users/cxhuan/Documents/python_workspace/stock/test.py", line 47, in diyException raise Exception("error level", level) #主動拋出一個異常,而且帶有參數Exception: ('error level', 2)
除了使用 Python 內置的異常,咱們還能夠建立本身的異常類型。建立本身的異常很是簡單,只須要建立一個類,並繼承 Exception 類或其子類。
下面的代碼建立了一個異常 DiyError 繼承自 Python 內置的 RuntimeError,用於在異常觸發時輸出更多的信息。
#自定義異常class DiyError(RuntimeError): def __init__(self, arg): self.args = arg
try: raise DiyError("my diy exception") #觸發異常except DiyError as e: print(e)
定義好了以後,咱們就能夠在 except 語句後使用 DiyError 異常,變量 e 是用於建立 DiyError 類的實例。咱們也能夠經過 raise 語句手動觸發這個異常。
一些對象定義了標準的清理行爲,不管系統是否成功的使用了它,一旦不須要它了,那麼這個標準的清理行爲就會執行。
for line in open("myfile.txt"): print(line, end="")
上面這個例子嘗試打開一個文件,而後把內容打印出來。可是有一個問題:當執行完畢後,程序沒有關閉文件流,文件會保持打開狀態。
關鍵詞 with 語句就能夠保證諸如文件之類的對象在使用完以後必定會正確的執行他的清理方法。
with open("myfile.txt") as f: for line in f: print(line, end="")
以上這段代碼執行完畢後,就算在處理過程當中出問題了,文件 f 老是會關閉。這裏面的原理就是使用了 finally 機制,有興趣的能夠去深刻了解一下。
本節給你們介紹了 Python 錯誤和異常的使用,掌握了錯誤和異常的處理,能夠極大地提升程序的健壯性,爲程序的持續完整運行提供了保障。
系列文章