Python中的異常(Exception)處理


異常

當你的程序出現例外情況時就會發生異常(Exception)。例如,當你想要讀取一個文件時,而那個文件卻不存在,怎么辦?又或者你在程序執行時不小心把它刪除了,怎么辦?這些通過使用異常來進行處理。

類似地,如果你的程序中出現了一些無效的語句該怎么辦?Python 將會對此進行處理,舉起(Raises)它的小手來告訴你哪里出現了一個錯誤(Error)。

錯誤

你可以想象一個簡單的 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 為這個錯誤所做的事情。

異常

我們將嘗試(Try)去讀取用戶的輸入內容。按下 [ctrl-d] 來看看會發生什么事情。

>>> 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 實現)在不該出現的時候出現了。

處理異常

我們可以通過使用 try..except 來處理異常狀況。一般來說我們會把通常的語句放在 try 代碼塊中,將我們的錯誤處理器代碼放置在 except 代碼塊中。

案例(保存文 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))

 

輸出:

# 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 子句將在沒有發生異常的時候執行。

在下一個案例中,我們還將了解如何獲取異常對象以便我們可以檢索其他信息。

拋出異常3

你可以通過 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 字段來向用戶打印一條合適的信息。

Try ... Finally

假設你正在你的讀取中讀取一份文件。你應該如何確保文件對象被正確關閉,無論是否會發生異常?這可以通過 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(),以便它能被立即打印到屏幕上。

with 語句

在 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 的標准庫。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM