try、raise 陳述句


以下這個程式,預期使用者要輸入整數:
input = int(input('輸入整數:'))
print('{0} 為 {1}'.format(input, '奇數' if input % 2 else '偶數'))

如果使用者輸入的不是整數,就會出現錯誤:
輸入整數:one
Traceback (most recent call last):
  File "demo.py", line 1, in <module>
    input = int(input('輸入整數:'))
ValueError: invalid literal for int() with base 10: 'one'


在Python中程式若發生錯誤,會丟出例外事件,以上例而言就是引發(Raise)ValueError物件,如果程式沒有處理例外而丟出至執行環境,則會顯示例外追蹤(Traceback)並中斷程式。如果你想要處理例外,則可以使用try...except語句。例如:
try:
input = int(input('輸入整數:'))
print('{0} 為 {1}'.format(input, '奇數' if input % 2 else '偶數'))
except ValueError:
print('請輸入阿拉伯數字')

如果使用者輸入錯誤,引發的ValueError物件會被except比對型態是否相同,如果相同則執行對應的區塊。以上例而言,如果使用者輸入錯誤,就會顯示較友善的提示訊息(而不是丟個使用者看不懂的追蹤訊息):
輸入整數:one
請輸入阿拉伯數字


try..except的except可以指定多個物件,也可以有多個except,如果沒有指定except後的物件型態,則表示捕捉所有引發的物件。舉例來說,上例中若使用者於輸入時輸入Ctrl+Z,在Windows環境下會引發EOFError,若輸入Ctrl+C,則會引發KeyboardInterrupt。下例中處理這些可能的狀況:
import traceback
try:
input = int(input('輸入整數:'))
print('{0} 為 {1}'.format(input, '奇數' if input % 2 else '偶數'))
except ValueError:
print('請輸入阿拉伯數字')
except (EOFError, KeyboardInterrupt):
print('使用者中斷程式')
except:
print('不明的程式中斷')
traceback.print_exc()

由於except會捕捉所有引發的物件,所以必須置於最後。traceback.print_exc()則可以顯示例外的追蹤訊息。try還可以搭配finally,一但設置,無論有無引發物件,finally區塊一定會執行,這通常用來作為關閉若干資源的區塊,例如關閉檔案:
file = open('demo.py', 'r', encoding='UTF-8')
try:
for line in file:
print(line, end='')
except:
print('讀取檔案發生錯誤')
finally:
file.close()

try也可以搭配else區塊,如果try區塊中沒有任何的錯誤發生,則會執行else區塊:
try:
    statement
except some:
    statement
except:
    statement
else:
    statement
finally:
    statement

你可以使用raise自行引發例外。例如:
>>> try:
...     raise EOFError
... except EOFError:
...     print('EOFError')
...
EOFError
>>>