天天看點

簡明Python3教程 15.異常

簡介

當程式發生意外情況時則産生異常。

例如你需要讀一個檔案而這個檔案并不存在會咋樣?又或者是程式運作時你把它誤删除了呢?

上述情形通過異常進行處理。

類似的,如果你的程式存在一些非法語句會發生什麼呢?這時python會舉手告訴你存在一個錯誤。

錯誤

考慮一個簡單的print函數調用。如果我們把print錯拼成Print(注意大小寫),這時python将引發一個文法錯誤。

    >>> Print('Hello World')

    Traceback (most recent call last):

      File "<pyshell#0>", line 1, in <module>

        Print('Hello World')

    NameError: name 'Print' is not defined

    >>> print('Hello World')

    Hello World

我們看到一個NameError被引發并且發生錯誤的位置也被列印出來。這就是一個錯誤處理器(error handler)為這個錯誤所進行的處理。

異常

我們嘗試從使用者讀取輸入,看看當鍵入ctrl-d(注:windows使用者輸入ctrl-z)時會發生什麼。

    >>> s = input('Enter something --> ')

    Enter something -->

      File "<pyshell#2>", line 1, in <module>

        s = input('Enter something --> ')

EOFError: EOF when reading a line

(注:也許你看到的資訊會所有不同,但隻要引發了EOFError即可)

可以看到python引發了一個被稱作EOFError的異常,一般這意味着它遇到了一個非期望的檔案尾(end of file)符号(注:windows下為ctrl-z)

處理異常

利用try...except語句使得我們可以處理異常。通常我們将語句放入try塊而将錯誤處理放到except塊中。

#!/usr/bin/python

# Filename: try_except.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 {0}'.format(text))

輸出:

    $ python try_except.py

    Enter something -->     # Press ctrl-d

    Why did you do an EOF on me?

    Enter something -->     # Press ctrl-c

    You cancelled the operation.

    Enter something --> no exceptions

    You entered no exceptions

代碼如何工作:

我們将可能引起異常/錯誤的所有語句放入try塊,然後将适當的錯誤/異常處理器放進except塊/從句中。

except從句可以處理一個單一的指定的錯誤或異常,或者一組括在小括号中的異常/錯誤。

如果沒有給出異常或錯誤,則except會處理所有的錯誤和異常。

注意每個try至少要關聯一個except從句,否則隻存在try塊有啥意義呢?

任何沒有被處理的錯誤或異常都會導緻python預設處理器的調用,它的作用僅僅是終止程式運作并将錯誤資訊列印出來。前面我們已經見識過了。

你還可以為try..except塊關聯一個else從句。如果沒有異常發生則else塊被執行。

下面的例子中,我們将看到如何得到異常對象擷取額外的異常資訊。

引發異常

通過raise語句你可以引發異常。為raise語句提供錯誤/異常名後異常對象會被抛出。

你抛出的錯誤或異常必須是一個間接或直接派生自Exception類的類。

# 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

    if len(text) < 3:

        raise ShortInputException(len(text), 3)

    # Other work can continue as usual here

except ShortInputException as ex:

    print('ShortInputException: The input was {0} long, expected at

least {1}'/

          .format(ex.length, ex.atleast))

    print('No exception was raised.')

    $ python raising.py

    Enter something --> a

    ShortInputException: The input was 1 long, expected at least 3

    Enter something --> abc

    No exception was raised.

範例如何工作:

這裡,我們建立了自己的異常類型。這個新的異常類型被稱作ShortInputException。

ShortInputException擁有兩個字段 – length指出給定輸入的長度,而atleast為程式希望輸入的最小長度。

在except從句中,我們給定異常類并将其對象存儲為一個變量。這就類似于函數調用中的形參與實參。

在這個特定的except從句中,我們利用異常對象的length和atleast字段向使用者列印出适當的提示資訊。

try...finally

假設你的程式正在讀取一個檔案。如何保證無論是否發生異常檔案對象都能被适當的關閉?這可以通過finally塊做到。

注意你可以同時為try塊關聯except和finally塊。如果你希望同時使用兩者則必須将一個嵌入另一個中。

# Filename: finally.py

import time

    f = open('poem.txt')

    while True: # our usual file-reading idiom

        line = f.readline()

        if len(line) == 0:

            break

        print(line, end='')

        time.sleep(2) # To make sure it runs for a while

    print('!! You cancelled the reading from the file.')

finally:

    f.close()

    print('(Cleaning up: Closed the file)')

    $ python finally.py

    Programming is fun

    When the work is done

    if you wanna make your work also fun:

    !! You cancelled the reading from the file.

    (Cleaning up: Closed the file)

我們執行一個常見的讀檔案操作,但故意在列印每行後利用time.sleep函數讓程式休眠2秒,是以程式會運作的比較慢。

當程式運作時輸入ctrl-c将中斷/取消程式的運作。

注意ctrl-c會導緻抛出KeyboardInterrupt異常,随後程式結束。但在程式結束前finally會被執行是以檔案對象永遠都會被關閉。

with語句

在try塊中獲得資源後在finally塊中釋放之是很常見的設計方式。是以python提供with語句給予更簡潔的實作方式。

# Filename: using_with.py

with open("poem.txt") as f:

    for line in f:

程式的輸出應該和上面的範例相同。程式的不同之處在于我們在with語句中使用open函數 – 如此with語句就會自動關閉檔案了。

在幕後with與使用者有一個協定。它将讀取open語句傳回的對象,這裡我們将這個對象稱為”thefile”

在with塊的開始處,with永遠都會調用thefile.__enter__方法而在塊結束處又會調用thefile.__exit__方法。

是以我們在finally塊中的代碼被委托給__exit__方法了。這将幫助我們避免反複的使用try..finally塊。

小結

我們已經讨論了try...except和try...finally的用法。并了解到如何建立自己的異常類型與引發異常。

下面,我們将研究python标準庫。

--------------Python書籍推薦-----------------

Python基礎教程-第2版.修訂版 

簡明Python3教程 15.異常

PYTHON核心程式設計

簡明Python3教程 15.異常

零基礎學Python

簡明Python3教程 15.異常