當(dāng)你的程序中出現(xiàn)某些 異常的 狀況的時(shí)候,異常就發(fā)生了。例如,當(dāng)你想要讀某個(gè)文件的時(shí)候,而那個(gè)文件不存在?;蛘咴诔绦蜻\(yùn)行的時(shí)候,你不小心把它刪除了。上述這些情況可以使用異常來處理。
假如你的程序中有一些無效的語句,會(huì)怎么樣呢?Python 會(huì)引發(fā)并告訴你那里有一個(gè)錯(cuò)誤,從而處理這樣的情況。
慮一個(gè)簡單的 print 語句。假如我們把 print 誤拼為 Print,注意大寫,這樣 Python 會(huì) 引發(fā) 一個(gè)語法錯(cuò)誤。
>>> Print 'Hello World'
File "<stdin>", line 1
Print 'Hello World'
^
SyntaxError: invalid syntax
>>> print 'Hello World'
Hello World
我們可以觀察到有一個(gè) SyntaxError 被引發(fā),并且檢測到的錯(cuò)誤位置也被打印了出來。這是這個(gè)錯(cuò)誤的 錯(cuò)誤處理器 所做的工作。
我們嘗試讀取用戶的一段輸入。按 Ctrl-d,看一下會(huì)發(fā)生什么。
>>> s = raw_input('Enter something --> ')
Enter something --> Traceback (most recent call last):
File "<stdin>", line 1, in ?
EOFError
Python 引發(fā)了一個(gè)稱為 EOFError 的錯(cuò)誤,這個(gè)錯(cuò)誤基本上意味著它發(fā)現(xiàn)一個(gè)不期望的 文件尾 (由 Ctrl-d 表示)
接下來,我們將學(xué)習(xí)如何處理這樣的錯(cuò)誤。
我們可以使用 try..except 語句來處理異常。我們把通常的語句放在 try-塊中,而把我們的錯(cuò)誤處理語句放在 except-塊中。
例 13.1 處理異常
#!/usr/bin/python
# Filename: try_except.py
import sys
try:
s = raw_input('Enter something --> ')
except EOFError:
print '\nWhy did you do an EOF on me?'
sys.exit() # exit the program
except:
print '\nSome error/exception occurred.'
# here, we are not exiting the program
print 'Done'
(源文件:code/try_except.py)
輸出
$ python try_except.py
Enter something -->
Why did you do an EOF on me?
$ python try_except.py
Enter something --> Python is exceptional!
Done
它如何工作
我們把所有可能引發(fā)錯(cuò)誤的語句放在 try 塊中,然后在 except 從句/塊中處理所有的錯(cuò)誤和異常。 except 從句可以專門處理單一的錯(cuò)誤或異常,或者一組包括在圓括號(hào)內(nèi)的錯(cuò)誤/異常。如果沒有給出錯(cuò)誤或異常的名稱,它會(huì)處理 所有的 錯(cuò)誤和異常。對(duì)于每個(gè) try 從句,至少都有一個(gè)相關(guān)聯(lián)的 except 從句。
如果某個(gè)錯(cuò)誤或異常沒有被處理,默認(rèn)的 Python 處理器就會(huì)被調(diào)用。它會(huì)終止程序的運(yùn)行,并且打印一個(gè)消息,我們已經(jīng)看到了這樣的處理。
你還可以讓 try..catch 塊關(guān)聯(lián)上一個(gè) else 從句。當(dāng)沒有異常發(fā)生的時(shí)候,else 從句將被執(zhí)行。
我們還可以得到異常對(duì)象,從而獲取更多有個(gè)這個(gè)異常的信息。這會(huì)在下一個(gè)例子中說明。
你可以使用 raise 語句 引發(fā) 異常。你還得指明錯(cuò)誤/異常的名稱和伴隨異常 觸發(fā)的 異常對(duì)象。你可以引發(fā)的錯(cuò)誤或異常應(yīng)該分別是一個(gè) Error 或 Exception 類的直接或間接導(dǎo)出類。
例 13.2 如何引發(fā)異常
#!/usr/bin/python
# Filename: raising.py
class ShortInputException(Exception):
'''A user-defined exception class.'''
def __init__(self, length, atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast
try:
s = raw_input('Enter something --> ')
if len(s) < 3:
raise ShortInputException(len(s), 3)
# Other work can continue as usual here
except EOFError:
print '\nWhy did you do an EOF on me?'
except ShortInputException, x:
print 'ShortInputException: The input was of length %d, \
was expecting at least %d' % (x.length, x.atleast)
else:
print 'No exception was raised.'
源文件(code/raising.py)
輸出
$ python raising.py
Enter something -->
Why did you do an EOF on me?
$ python raising.py
Enter something --> ab
ShortInputException: The input was of length 2, was expecting at least 3
$ python raising.py
Enter something --> abc
No exception was raised.
它如何工作
這里,我們創(chuàng)建了我們自己的異常類型,其實(shí)我們可以使用任何預(yù)定義的異常/錯(cuò)誤。這個(gè)新的異常類型是 ShortInputException 類。它有兩個(gè)域—— length 是給定輸入的長度,atleast 則是程序期望的最小長度。
在 except 從句中,我們提供了錯(cuò)誤類和用來表示錯(cuò)誤/異常對(duì)象的變量。這與函數(shù)調(diào)用中的形參和實(shí)參概念類似。在這個(gè)特別的 except 從句中,我們使用異常對(duì)象的 length 和 atleast 域來為用戶打印一個(gè)恰當(dāng)?shù)南ⅰ?/p>
假如你在讀一個(gè)文件的時(shí)候,希望在無論異常發(fā)生與否的情況下都關(guān)閉文件,該怎么做呢?這可以使用 finally 塊來完成。注意,在一個(gè) try 塊下,你可以同時(shí)使用 except 從句和 finally 塊。如果你要同時(shí)使用它們的話,需要把一個(gè)嵌入另外一個(gè)。
例 13.3 使用finally
#!/usr/bin/python
# Filename: finally.py
import time
try:
f = file('poem.txt')
while True: # our usual file-reading idiom
line = f.readline()
if len(line) == 0:
break
time.sleep(2)
print line,
finally:
f.close()
print 'Cleaning up...closed the file'
(源文件:code/finally.py)
輸出
$ python finally.py
Programming is fun
When the work is done
Cleaning up...closed the file
Traceback (most recent call last):
File "finally.py", line 12, in ?
time.sleep(2)
KeyboardInterrupt
它如何工作
我們進(jìn)行通常的讀文件工作,但是我有意在每打印一行之前用 time.sleep 方法暫停2秒鐘。這樣做的原因是讓程序運(yùn)行得慢一些(Python 由于其本質(zhì)通常運(yùn)行得很快)。在程序運(yùn)行的時(shí)候,按 Ctrl-c 中斷/取消程序。
我們可以觀察到 KeyboardInterrupt 異常被觸發(fā),程序退出。但是在程序退出之前,finally 從句仍然被執(zhí)行,把文件關(guān)閉
我們已經(jīng)討論了 try..except 和 try..finally 語句的用法。我們還學(xué)習(xí)了如何創(chuàng)建我們自己的異常類型和如何引發(fā)異常。
接下來,我們將探索 Python 標(biāo)準(zhǔn)庫。