當你的程序出現例外狀況時就會發生異常(Exception)。例如,當你想要讀取一個文件時,而那個文件卻不存在,怎麼辦?又或者你在程序執行時不當心把它刪除了,怎麼辦?這些經過使用異常來進行處理。html
相似地,若是你的程序中出現了一些無效的語句該怎麼辦?Python 將會對此進行處理,舉起(Raises)它的小手來告訴你哪裏出現了一個錯誤(Error)。python
你能夠想象一個簡單的 print 函數調用。若是咱們把 print 誤拼成 Print 會怎樣?你會注意到它的首字母是大寫。在這一例子中,Python 會拋出(Raise)一個語法錯誤。函數
>>> Print("Hello World") Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'Print' is not defined >>> print("Hello World") Hello World
你會注意到一個 NameError 錯誤被拋出,同時 Python 還會打印出檢測到的錯誤發生的位置。這就是一個錯誤錯誤處理器(Error Handler)2 爲這個錯誤所作的事情。spa
咱們將嘗試(Try)去讀取用戶的輸入內容。按下 [ctrl-d] 來看看會發生什麼事情。code
>>> s = input('Enter something --> ') Enter something --> Traceback (most recent call last): File "<stdin>", line 1, in <module> EOFError
此處 Python 指出了一個稱做 EOFError 的錯誤,表明着它發現了一個文件結尾(End of File)符號(由 ctrl-d 實現)在不應出現的時候出現了。orm
咱們能夠經過使用 try..except 來處理異常情況。通常來講咱們會把一般的語句放在 try 代碼塊中,將咱們的錯誤處理器代碼放置在 except 代碼塊中。htm
案例(保存文 exceptions_handle.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 {}'.format(text))
輸出:blog
# Press ctrl + d $ python exceptions_handle.py Enter something --> Why did you do an EOF on me? # Press ctrl + c $ python exceptions_handle.py Enter something --> ^CYou cancelled the operation. $ python exceptions_handle.py Enter something --> No exceptions You entered No exceptions
它是如何工做的教程
咱們將全部可能引起異常或錯誤的語句放在 try 代碼塊中,並將相應的錯誤或異常的處理器(Handler)放在 except 子句或代碼塊中。except 子句能夠處理某種特定的錯誤或異常,或者是一個在括號中列出的錯誤或異常。若是沒有提供錯誤或異常的名稱,它將處理全部錯誤與異常。
要注意到必須至少有一句 except 字句與每一句 try 字句相關聯。否則,有一個 try 代碼塊又有什麼意義?
若是沒有任何錯誤或異常被處理,那麼將調用 Python 默認處理器,它只會終端程序執行並打印出錯誤信息。咱們已經在前面的章節裏見過了這種處理方式。
你還能夠擁有一個 else 子句與 try..except 代碼塊相關聯。else 子句將在沒有發生異常的時候執行。
在下一個案例中,咱們還將瞭解如何獲取異常對象以便咱們能夠檢索其餘信息。
你能夠經過 raise 語句來引起一次異常,具體方法是提供錯誤名或異常名以及要拋出(Thrown)異常的對象。
你可以引起的錯誤或異常必須是直接或間接從屬於 Exception(異常) 類的python 派生類。
案例(保存爲 exceptions_raise.py):
# encoding=UTF-8 class ShortInputException(Exception): '''一個由用戶定義的異常類''' def __init__(self, length, atleast): Exception.__init__(self) self.length = length self.atleast = atleast try: text = input('Enter something --> ') if len(text) < 3: raise ShortInputException(len(text), 3) # 其餘工做能在此處繼續正常運行 except EOFError: print('Why did you do an EOF on me?') except ShortInputException as ex: print(('ShortInputException: The input was ' + '{0} long, expected at least {1}') .format(ex.length, ex.atleast)) else: print('No exception was raised.')
輸出:
$ python exceptions_raise.py Enter something --> a ShortInputException: The input was 1 long, expected at least 3 $ python exceptions_raise.py Enter something --> abc No exception was raised.
它是如何工做的
在本例中,咱們建立了咱們本身的異常類型。這一新的異常類型叫做 ShortInputException。它包含兩個字段——獲取給定輸入文本長度的 length,程序指望的最小長度 atleast。
在 except 子句中,咱們說起了錯誤類,將該類存儲 as(爲) 相應的錯誤名或異常名。這相似於函數調用中的形參與實參。在這個特殊的 except 子句中咱們使用異常對象的 length 與 atleast 字段來向用戶打印一條合適的信息。
假設你正在你的讀取中讀取一份文件。你應該如何確保文件對象被正確關閉,不管是否會發生異常?這能夠經過 finally 塊來完成。
保存該程序爲 exceptions_finally.py:
import sys import time f = None try: f = open("poem.txt") # 咱們經常使用的文件閱讀風格 while True: line = f.readline() if len(line) == 0: break print(line, end='') sys.stdout.flush() print("Press ctrl+c now") # 爲了確保它能運行一段時間 time.sleep(2) except IOError: print("Could not find file poem.txt") except KeyboardInterrupt: print("!! You cancelled the reading from the file.") finally: if f: f.close() print("(Cleaning up: Closed the file)")
輸出:
$ python exceptions_finally.py Programming is fun Press ctrl+c now ^C!! You cancelled the reading from the file. (Cleaning up: Closed the file)
它是如何工做的
咱們按照一般文件讀取進行操做,可是咱們同時經過使用 time.sleep 函數任意在每打印一行後插入兩秒休眠,使得程序運行變得緩慢(在一般狀況下 Python 運行得很是快速)。當程序在處在運行過過程當中時,按下 ctrl + c 來中斷或取消程序。
你會注意到 KeyboardInterrupt 異常被拋出,爾後程序退出。不過,在程序退出以前,finally 子句獲得執行,文件對象總會被關閉。
另外要注意到咱們在 print 以後使用了 sys.stout.flush(),以便它能被當即打印到屏幕上。
在 try 塊中獲取資源,而後在 finally 塊中釋放資源是一種常見的模式。所以,還有一個 with 語句使得這一過程能夠以一種乾淨的姿態得以完成。
保存爲 exceptions_using_with.py:
with open("poem.txt") as f: for line in f: print(line, end='')
它是如何工做的
程序輸出的內容應與上一個案例所呈現的相同。本例的不一樣之處在於咱們使用的是 open 函數與 with 語句——咱們將關閉文件的操做交由 with open 來自動完成。
在幕後發生的事情是有一項 with 語句所使用的協議(Protocol)。它會獲取由 open 語句返回的對象,在本案例中就是「thefile」。
它總會在代碼塊開始以前調用 thefile.__enter__ 函數,而且總會在代碼塊執行完畢以後調用 thefile.__exit__。
所以,咱們在 finally 代碼塊中編寫的代碼應該格外留心 __exit__ 方法的自動操做。這可以幫助咱們避免重複顯式使用 try..finally 語句。
有關Python教程中這話題的更多討論已經超出了本書所能涉及的範圍,所以請參考 PEP 343 來了解更加全面的解釋。
咱們已經討論了 try..except 和 try..finally 語句的用法。同時咱們也已經看到了如何建立咱們本身的python 異常類型,還有如何拋出異常。
接下來,咱們將探索 Python 的標準庫。