在寫python代碼的過程當中可能會出現一些錯誤,這些錯誤可區分爲2類:語法錯誤 和 異常~html
>>> a = 2 >>> if a > 0 print('OK'); File "<stdin>", line 1 if a > 0 print('OK'); ^ SyntaxError: invalid syntax
如上語句即 存在語法錯誤,if 語句的條件後面沒有冒號 ‘:’。
語法錯誤也稱爲解析錯誤,這類錯誤在程序執行以前就會被Python解釋器檢測到。若是使用IDE工具開發(例如 pycharm),pycharm會直接使用下標的紅線提示開發者這裏存在語法錯誤。這類錯誤必須在程序運行前就改正~python
代碼不存在語法錯誤,在運行過程當中出現的邏輯錯誤,即爲異常~mysql
>>> 1 / 0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero >>> >>> >>> lst = ['a', 'b', 'c'] >>> lst[2] 'c' >>> lst[3] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
程序在運行過程當中,一旦發生異常,且發生的異常沒有被捕獲或者處理,則程序就會中止運行。
異常有不一樣的類型,在發生異常時,異常的類型及發生異常的緣由 會被打印出來。上述示例中,第一個異常爲 ZeroDivisionError(除數不能爲0),第二個異常爲 IndexError(列表指針超出範圍)。
ZeroDivisionError 和 IndexError 都爲Python的內置異常,即 python解釋器 已經定義好的異常類型,常見的內置異常還有:StopIteration,GeneratorExit,AssertionError,EOFError,IOError,OSError等等。關於Python的內置異常及說明可參閱:https://docs.python.org/zh-cn/3.7/library/exceptions.html#bltin-exceptions
sql
這些內置異常都繼承於Exception類(自定義的異常通常也是直接或間接地繼承自Exception類),且全部 內置異常的名稱都存在於 內置名稱空間中,可直接使用,而不須要 'import exceptions模塊'。數據庫
try...except... 語句用於捕獲異常 及 對異常的處理。這樣程序在發生異常時,可針對性的作出處理,避免程序的中斷~,try...except... 語句的語法以下:express
try: 可能發生異常的語句塊 except [異常類型1]: 處理異常1的語句 except [異常類型2]: 處理異常2的語句
示例:ide
try: a = 1/0 except ZeroDivisionError: print('除數不能爲0')
try...except... 語句的工做原理以下:函數
try: num = int(input("Enter a number: ")) # 這裏可能會發生 ValueError 異常 a = 1/0 except ZeroDivisionError: print('除數不能爲0')
對於可能會先發生的 ValueError 異常,異常類型和 except 關鍵字後面的異常不匹配,那麼這個 異常 將不會被 這個except 捕獲,因而這個異常就會被傳遞到外部~,結果輸出以下:工具
Enter a number: abc Traceback (most recent call last): File "...test.py", line 9, in <module> num = int(input("Enter a number: ")) # 這裏可能會發生 ValueError ValueError: invalid literal for int() with base 10: 'abc'
這個時候,可使用多個 except 來捕獲異常:指針
try: num = int(input("Enter a number: ")) # 這裏可能會發生 ValueError a = 1/0 except ZeroDivisionError: print('除數不能爲0') except ValueError: print('請輸入數字~') # 結果輸出: Enter a number: abc 請輸入數字~
固然也可使用一個萬能異常 Exception 來處理。因爲內置異常和自定義異常都直接或間接地繼承自 Exception,因此 Exception 能夠用來匹配任何異常。這樣作的優點在於 能夠針對全部的異常統一進行捕獲,缺點在於 不能針對指定的異常作出相應的處理,而是統一使用一種方式進行處理~
try: num = int(input("Enter a number: ")) a = 1/0 except Exception: pass
在實際的應用中,通常這兩種方式會被結合使用:針對指定的那麼幾個異常分別進行捕獲並作相應的處理,剩下的全部異常都統一使用 Exception 來捕獲~
try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print(err) except ValueError: print("數據類型沒法轉換") except Exception: print('Unexpected error')
最後的 Exception異常名 也能夠省略不寫(默認就是 Exception )
except: print('Unexpected error')
異常發生時,都會有關於這個異常的具體描述信息,異常的描述信息可經過 as 關鍵字獲取,這個在上述示例中已經有使用~
try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print(err) # 若文件不存在,或有以下輸出: [Errno 2] No such file or directory: 'myfile.txt'
else 爲可選字句,放在 except 字句後面,若 try 語句塊中沒有異常發生,則會執行else 語句塊中的代碼~
try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print(err) else: f.close() # try 語句塊正常執行完成後,關閉打開的文件
finally 也爲可選字句,放在全部語句塊的最後。無論 try 語句塊中是否觸發異常,都會執行 finally 語句塊中的代碼。finally 語句塊中的代碼通常都用於 關閉系統資源,例如關閉文件,關閉數據庫鏈接等~
def connDB(): try: conn = pymysql.connect(host=HOST, user=USER, password=PASSWD, database=DATEBASE, charset='utf8', cursorclass=pymysql.cursors.DictCursor) return conn except Exception: logger.error("can not connect to database!") exit() db = connDB() try: ... pass except: ... pass finally: db.close()
在操做文件時,還可使用 with...as... 語句來自動關閉文件,即無論 with語句塊 中是否觸發異常,with語句塊執行完畢後都會自動關閉文件~
try: f = open('myfile.txt', mode='r') a = 1/0 except Exception: print(f.closed) # False,當 try語句塊中發生異常,文件沒有被關閉 ############## try: with open('myfile.txt', mode='r') as f: a = 1 / 0 except Exception: print(f.closed) # True,文件已經自動關閉
raise語句用於手動觸發異常,觸發的異常能夠經過傳遞參數說明異常的緣由,例如:
>>> raise IndexError('lst out of range') Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: lst out of range
在 except語句塊中,若不想對捕獲的異常進行處理,則可使用 raise語句 從新觸發異常,由外層的 try語句來進行處理~
try: raise ZeroDivisionError('abc') except ZeroDivisionError: print('除數爲0') raise # 更簡單的寫法,從新觸發捕獲到的異常
assert語法:
assert expression
assert 關鍵字根據後面的表達式的真假來肯定程序是否繼續往下執行。若表達式返回爲True,則程序繼續往下執行,若爲False,則觸發 AssertionError 異常~
print('start...') assert 1 == 1 print('end...') # 輸出結果: start... end... ################ print('start...') assert 1 == 2 print('end...') # 輸出結果: start... Traceback (most recent call last): File ".../test.py", line 17, in <module> assert 1 == 2 AssertionError
經過繼承 Exception 類來建立自定義的異常;自定義異常應該儘可能保持異常類的簡單,通常自定義異常僅用於提取特有的錯誤信息~。自定義異常示例以下:
class MyError(Exception): def __init__(self, ErrorInfo): Exception.__init__(self) self.errorinfo=ErrorInfo def __str__(self): return self.errorinfo
注意:自定義的異常類只能經過 raise關鍵字 來手動觸發。
使用 traceback 關鍵字追蹤異常,須要導入 traceback 模塊(import traceback)。
import traceback try: f = open('myfile.txt', mode='r') a = 1/0 except Exception: traceback.print_exc() logger.error(traceback.format_exc()) #使用日誌模塊記錄 異常的詳細信息,或使用 traceback.print_exc(file=path) 記錄到指定文件 # 輸出信息以下: Traceback (most recent call last): File "/Users/luyi/PycharmProjects/untitled/day26/test.py", line 12, in <module> a = 1/0 ZeroDivisionError: division by zero
這裏異常信息的輸出和不捕獲異常時候系統的輸出一致,其實 traceback.print_exc() 函數調用了sys.exc_info() 函數來完成 異常信息的輸出,traceback.print_exc()的源碼以下:
def print_exc(limit=None, file=None): """Shorthand for 'print_exception(sys.exc_type, sys.exc_value, sys.exc_traceback, limit, file)'. (In fact, it uses sys.exc_info() to retrieve the same information in a thread-safe way.)""" if file is None: file = sys.stderr try: etype, value, tb = sys.exc_info() # 調用了 sys.exc_info() 函數 print_exception(etype, value, tb, limit, file) finally: etype = value = tb = None
.................^_^