1. 程式人生 > >第033講:異常處理:你不可能總是對的2

第033講:異常處理:你不可能總是對的2

目錄

0. 請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!

測試題

0. 我們使用什麼方法來處理程式中出現的異常?

1. 一個 try 語句可以和多個 except 語句搭配嗎?為什麼?g

2. 你知道如何統一處理多類異常嗎?

3. except 後邊如果不帶任何異常類,Python 會捕獲所有(try 語句塊內)的異常並統一處理,但小甲魚卻不建議這麼做,你知道為什麼嗎?

4. 如果異常發生在成功開啟檔案後,Python 跳到 except 語句執行,並沒有執行關閉檔案的命令(使用者寫入檔案的資料就可能沒有儲存起來),因此我們需要確保無論如何(就算出了異常退出)檔案也要被關閉,我們應該怎麼做呢?}

5. 請恢復以下程式碼中馬賽克擋住的內容,使得程式執行後可以按要求輸出。

動動手

0. 還記得我們第一個小遊戲嗎?只要使用者輸入非整型資料,程式立刻就會蹦出不和諧的異常資訊然後崩潰。請使用剛學的異常處理方法修改以下程式,提高使用者體驗。.

1. input() 函式有可能產生兩類異常:EOFError(檔案末尾endoffile,當用戶按下組合鍵 Ctrl+d 產生)和 KeyboardInterrupt(取消輸入,當用戶按下組合鍵 Ctrl+c 產生),再次修改上邊程式碼,捕獲處理 input() 的兩類異常,提高使用者體驗。

2. 嘗試一個新的函式 int_input(),當用戶輸入整數的時候正常返回,否則提示出錯並要求重新輸入。%

3. 把檔案關閉放在 finally 語句塊中執行還是會出現問題,像下邊這個程式碼,當前資料夾中並不存在"My_File.txt"這個檔案,那麼程式執行起來會發生什麼事情呢?你有辦法解決這個問題嗎?


0. 請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!

上節課我們已經掌握了能夠碰到的異常型別,name這一節我們就來學習如何檢測這些異常並處理它們。異常檢測我們可以使用 try 語句來實現,任何出現在 try 語句範圍內的異常都會被檢測到,我們這節課要介紹兩個模式的 try 語句,

一種是 try—except 語句:

語法:try :

                       檢測範圍

           except  Exception  [ as  reason ]:

                      出現異常(Exception)後的處理程式碼

try:
        f = open('我是一個不存在的檔案.txt')
        print(f.read())
        f.close
except OSError:
        print('檔案出錯啦')

============ RESTART: C:/Users/XiangyangDai/Desktop/上課程式碼/33-1.py ============
檔案出錯啦

這樣處理對於使用者來說很好,但是對於程式設計師來說,我們還想要知道報錯的具體錯誤型別,這時,我們就使用可選引數 as reason(其中 reason 是一個變數,得到錯誤具體,需要 str(reason) 才能列印)

try:
        f = open('我是一個不存在的檔案.txt')
        print(f.read())
        f.close
except OSError as reason:
        print('檔案出錯啦!\n錯誤的原因是:' + str(reason))

============ RESTART: C:/Users/XiangyangDai/Desktop/上課程式碼/33-1.py ============
檔案出錯啦!
錯誤的原因是:[Errno 2] No such file or directory: '我是一個不存在的檔案.txt'

另外,一個 try 可以與多個 except 搭配,以監測多種型別的錯誤。但是在這種情況下,程式會在第一個出錯的位置檢查有沒有對應的 except,如果有,就僅列印第一次出錯的出錯資訊,如果沒有第一個出錯對應的except,則還是紅色原始報錯。

try:
        sum = 1 + '1'
        f = open('我是一個不存在的檔案.txt')
        print(f.read())
        f.close
except OSError as reason:
        print('檔案出錯啦!\n錯誤的原因是:' + str(reason))
except TypeError as reason:
         print('型別出錯啦!\n錯誤的原因是:' + str(reason))
============ RESTART: C:/Users/XiangyangDai/Desktop/上課程式碼/33-1.py ============
型別出錯啦!
錯誤的原因是:unsupported operand type(s) for +: 'int' and 'str'

try:
        int('abc')    #ValueError
        sum = 1 + '1'    #型別錯誤 TypeError
        f = open('我是一個不存在的檔案.txt')  #OSError
        print(f.read())
        f.close
except OSError as reason:
        print('檔案出錯啦!\n錯誤的原因是:' + str(reason))
except TypeError as reason:
         print('型別出錯啦!\n錯誤的原因是:' + str(reason))
============ RESTART: C:/Users/XiangyangDai/Desktop/上課程式碼/33-1.py ============
Traceback (most recent call last):
  File "C:/Users/XiangyangDai/Desktop/上課程式碼/33-1.py", line 2, in <module>
    int('abc')    #ValueError
ValueError: invalid literal for int() with base 10: 'abc'

如果你想檢測任何型別的錯誤,只要程式出錯,就提示出錯資訊,不管是什麼型別的錯誤:

try:
        int('abc')    #ValueError
        sum = 1 + '1'    #型別錯誤 TypeError
        f = open('我是一個不存在的檔案.txt')  #OSError
        print(f.read())
        f.close
except :
        print('出錯啦!')

============ RESTART: C:/Users/XiangyangDai/Desktop/上課程式碼/33-1.py ============
出錯啦!

但是這種做法是不推薦的,因為這會隱藏程式設計師未想到的所有未準備好處理的異常和錯誤。例如當按住 ctrl + C 想停止程式時,也會檢測為KeyboardError,而彈出提示資訊。

要注意的是,try 語句的檢測範圍內一旦出現異常,剩下的語句將不會被執行。

第二種是 try — finally 語句:

語法:try:

                    檢測範圍

          except Exception [as reason]:

                   出現異常(Exception)後的處理程式碼

          finally:

                  無論如何都會被執行的程式碼

在上面的例子中,如果異常出現在開啟檔案之後,然後檔案沒有被關閉,這是非常不妥的。可以使用try — finally 語句改進。

try:
        f = open('C:\\Users\\XiangyangDai\\Desktop\\一個檔案.txt', 'w')
        print(f.write('我存在了!'))    #這裡會寫入‘我存在了!’列印的是寫入的字元數
        sum = 1 + '1'
except (OSError, TypeError):
        print('出錯啦!')
finally:
        f.close()
============ RESTART: C:/Users/XiangyangDai/Desktop/上課程式碼/33-2.py ============
5
出錯啦!

總結一下:如果 try 語句塊裡面沒有任何執行的錯誤的時候,就會跳過 exception語句塊,然後執行 finally 語句塊裡的內容,如果出現了異常,會根據異常的內容去找到對應的異常執行程式碼,然後還會執行 finally。也就是說,無論如何,finally語句塊裡的內容都是確保將被執行的內容。即使出現的異常在 exception 中沒有定義對應的處理程式碼,finally 也會被執行。

最後說一下 raise 語句:

可以使用 raise 語句引發一個異常

>>> raise
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    raise
RuntimeError: No active exception to reraise
>>> raise ZeroDivisionError('除數為零的異常')
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    raise ZeroDivisionError('除數為零的異常')
ZeroDivisionError: 除數為零的異常

測試題

0. 我們使用什麼方法來處理程式中出現的異常?

答:使用 try……except 搭配來捕獲處理程式中出現的異常。"Xj=$)R
try:版權屬於:bbs.fishc.com
        檢測範圍來自:bbs.fishc.com
except Exception[as reason]:r&Fijw]E
        出現異常(Exception)後的處理程式碼
Y%

1. 一個 try 語句可以和多個 except 語句搭配嗎?為什麼?g

答:可以。因為 try 語句塊中可能出現多類異常,利用多個 except 語句可以分別捕獲並處理我們感興趣的異常。

try:
    sum = 1 + '1'
    f = open('我是一個不存在的文件.txt')
    print(f.read())
    f.close()
except OSError as reason:
    print('檔案出錯啦T_T\n錯誤原因是:' + str(reason))
except TypeError as reason:
    print('型別出錯啦T_T\n錯誤原因是:' + str(reason))

2. 你知道如何統一處理多類異常嗎?

答:在 except 後邊使用小括號“()”把多個需要統一處理的異常括起來:

try:
    int('abc')
    sum = 1 + '1'
    f = open('我是一個不存在的文件.txt')
    print(f.read())
    f.close()
except (OSError, TypeError):
    print('出錯啦T_T\n錯誤原因是:' + str(reason))

3. except 後邊如果不帶任何異常類,Python 會捕獲所有(try 語句塊內)的異常並統一處理,但小甲魚卻不建議這麼做,你知道為什麼嗎?

答:因為它會隱藏所有程式設計師未想到並且未做好準備處理的錯誤,例如使用者輸入ctrl+c試圖終止程式會被解釋為KeyboardInterrupt異常。

4. 如果異常發生在成功開啟檔案後,Python 跳到 except 語句執行,並沒有執行關閉檔案的命令(使用者寫入檔案的資料就可能沒有儲存起來),因此我們需要確保無論如何(就算出了異常退出)檔案也要被關閉,我們應該怎麼做呢?}

答:我們可以使用 finally 語句來實現,如果 try 語句塊中沒有出現任何執行時錯誤,會跳過 except 語句塊執行 finally 語句塊的內容。

如果出現異常,則會先執行 except 語句塊的內容再接著執行 finally 語句塊的內容。總之,finally 語句塊裡的內容就是確保無論如何都將被執行的內容!

5. 請恢復以下程式碼中馬賽克擋住的內容,使得程式執行後可以按要求輸出。

程式碼:Powered by bbs.fishc.com

輸出:版權屬於:bbs.fishc.com

 答:這道題比較考腦瓜,你想到了嗎?

try:
    for i in range(3):
        for j in range(3):
            if i == 2:
                raise KeyboardInterrupt
            print(i, j)
except KeyboardInterrupt:
    print('退出啦!')

動動手

0. 還記得我們第一個小遊戲嗎?只要使用者輸入非整型資料,程式立刻就會蹦出不和諧的異常資訊然後崩潰。請使用剛學的異常處理方法修改以下程式,提高使用者體驗。.

猜數字小遊戲:

import random

secret = random.randint(1,10)
print('------------------我愛魚C工作室------------------')
temp = input("不妨猜一下小甲魚現在心裡想的是哪個數字:")
guess = int(temp)
while guess != secret:
    temp = input("哎呀,猜錯了,請重新輸入吧:")
    guess = int(temp)
    if guess == secret:
        print("我草,你是小甲魚心裡的蛔蟲嗎?!")
        print("哼,猜中了也沒有獎勵!")
    else:
        if guess > secret:
            print("哥,大了大了~~~")
        else:
            print("嘿,小了,小了~~~")
print("遊戲結束,不玩啦^_^")

答:這裡對可能導致異常的 guess = int(temp) 進行監測F&2()k"]
0PR3=c8!2xXw*Zl[Ir|sW<7"[email protected]
程式碼清單:

import random

secret = random.randint(1,10)
print('------------------我愛魚C工作室------------------')
temp = input("不妨猜一下小甲魚現在心裡想的是哪個數字:")
try:    
    guess = int(temp)
except ValueError:
    print('輸入錯誤!')
    guess = secret
while guess != secret:
    temp = input("哎呀,猜錯了,請重新輸入吧:")
    guess = int(temp)
    if guess == secret:
        print("我草,你是小甲魚心裡的蛔蟲嗎?!")
        print("哼,猜中了也沒有獎勵!")
    else:
        if guess > secret:
            print("哥,大了大了~~~")
        else:
            print("嘿,小了,小了~~~")
print("遊戲結束,不玩啦^_^")

1. input() 函式有可能產生兩類異常:EOFError(檔案末尾endoffile,當用戶按下組合鍵 Ctrl+d 產生)和 KeyboardInterrupt(取消輸入,當用戶按下組合鍵 Ctrl+c 產生),再次修改上邊程式碼,捕獲處理 input() 的兩類異常,提高使用者體驗。

答:

import random

secret = random.randint(1,10)
print('------------------我愛魚C工作室------------------')
try:
    temp = input("不妨猜一下小甲魚現在心裡想的是哪個數字:")    
    guess = int(temp)
except (ValueError, EOFError, KeyboardInterrupt):
    print('輸入錯誤!')
    guess = secret
while guess != secret:
    temp = input("哎呀,猜錯了,請重新輸入吧:")
    guess = int(temp)
    if guess == secret:
        print("我草,你是小甲魚心裡的蛔蟲嗎?!")
        print("哼,猜中了也沒有獎勵!")
    else:
        if guess > secret:
            print("哥,大了大了~~~")
        else:
            print("嘿,小了,小了~~~")
print("遊戲結束,不玩啦^_^")

2. 嘗試一個新的函式 int_input(),當用戶輸入整數的時候正常返回,否則提示出錯並要求重新輸入。%

程式實現如圖:版權屬於:bbs.fishc.com

 答:

def int_input(prompt=''):
    while True:
        try:
            int(input(prompt))
            break
        except ValueError:
            print('出錯,您輸入的不是整數!')

int_input('請輸入一個整數:')

3. 把檔案關閉放在 finally 語句塊中執行還是會出現問題,像下邊這個程式碼,當前資料夾中並不存在"My_File.txt"這個檔案,那麼程式執行起來會發生什麼事情呢?你有辦法解決這個問題嗎?

try:
    f = open('My_File.txt') # 當前資料夾中並不存在"My_File.txt"這個檔案T_T
    print(f.read())
except OSError as reason:
    print('出錯啦:' + str(reason))
finally:
f.close()

答:由於finally語句塊裡試圖去關閉一個並沒有成功開啟的檔案,因此會彈出錯誤內容如下:

>>> 出錯啦:[Errno 2] No such file or directory: 'My_File.txt'
Traceback (most recent call last):
  File "C:\Users\FishC000\Desktop\test.py", line 7, in <module>
    f.close()
NameError: name 'f' is not defined

我們這樣修正:

try:
    f = open('My_File.txt') # 當前資料夾中並不存在"My_File.txt"這個檔案T_T
    print(f.read())
except OSError as reason:
    print('出錯啦:' + str(reason))
finally:
    if 'f' in locals(): # 如果檔案物件變數存在當前區域性變數符號表的話,說明開啟成功
        f.close()