五種異常處理機制:try...except與try...finally


https://www.jb51.net/article/85627.htm

 https://www.jb51.net/article/60638.htm

http://c.biancheng.net/view/vip_7103.html

 

(try finally)

https://baijiahao.baidu.com/s?id=1636646977338815546&wfr=spider&for=pc   

http://www.360doc.com/content/19/0703/20/54508727_846532231.shtml   

https://www.cnblogs.com/windlazio/archive/2013/01/24/2874417.html

Python try except異常處理詳解

python標准異常

異常名稱 描述
BaseException 所有異常的基類
SystemExit 解釋器請求退出
KeyboardInterrupt 用戶中斷執行(通常是輸入^C)
Exception 常規錯誤的基類
StopIteration 迭代器沒有更多的值
GeneratorExit 生成器(generator)發生異常來通知退出
SystemExit Python 解釋器請求退出
StandardError 所有的內建標准異常的基類
ArithmeticError 所有數值計算錯誤的基類
FloatingPointError 浮點計算錯誤
OverflowError 數值運算超出最大限制
ZeroDivisionError 除(或取模)零 (所有數據類型)
AssertionError 斷言語句失敗
AttributeError 對象沒有這個屬性
EOFError 沒有內建輸入,到達EOF 標記
EnvironmentError 操作系統錯誤的基類
IOError 輸入/輸出操作失敗
OSError 操作系統錯誤
WindowsError 系統調用失敗
ImportError 導入模塊/對象失敗
KeyboardInterrupt 用戶中斷執行(通常是輸入^C)
LookupError 無效數據查詢的基類
IndexError 序列中沒有沒有此索引(index)
KeyError 映射中沒有這個鍵
MemoryError 內存溢出錯誤(對於Python 解釋器不是致命的)
NameError 未聲明/初始化對象 (沒有屬性)
UnboundLocalError 訪問未初始化的本地變量
ReferenceError 弱引用(Weak reference)試圖訪問已經垃圾回收了的對象
RuntimeError 一般的運行時錯誤
NotImplementedError 尚未實現的方法
SyntaxError Python 語法錯誤
IndentationError 縮進錯誤
TabError Tab 和空格混用
SystemError 一般的解釋器系統錯誤
TypeError 對類型無效的操作
ValueError 傳入無效的參數
UnicodeError Unicode 相關的錯誤
UnicodeDecodeError Unicode 解碼時的錯誤
UnicodeEncodeError Unicode 編碼時錯誤
UnicodeTranslateError Unicode 轉換時錯誤
Warning 警告的基類
DeprecationWarning 關於被棄用的特征的警告
FutureWarning 關於構造將來語義會有改變的警告
OverflowWarning 舊的關於自動提升為長整型(long)的警告
PendingDeprecationWarning 關於特性將會被廢棄的警告
RuntimeWarning 可疑的運行時行為(runtime behavior)的警告
SyntaxWarning 可疑的語法的警告
UserWarning 用戶代碼生成的警告

 

什么是異常?

異常即是一個事件,該事件會在程序執行過程中發生,影響了程序的正常執行。 

一般情況下,在Python無法正常處理程序時就會發生一個異常。

異常是Python對象,表示一個錯誤。

當Python腳本發生異常時我們需要捕獲處理它,否則程序會終止執行

 

什么是異常處理?

捕捉異常可以使用try/except語句。

try/except語句用來檢測try語句塊中的錯誤,從而讓except語句捕獲異常信息並處理。

如果你不想在異常發生時結束你的程序,只需在try里捕獲它。

 

 

當執行可能出錯的代碼時,需要適當的異常處理程序用於阻止潛在的錯誤發生。在異常可能發生的地方添加異常處理程序,對於用戶明確錯誤時一種好方法。即使不能例可解決問題,但是可以記錄運行環境並且停止程序運行。在你不能提供自己的異常捕獲代碼時,python會輸出錯誤消息和關於錯誤發生處的消息,再停止程序

>>> short_list=[1,2,3]
>>> position=5
>>> short_list[position]
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    short_list[position]
IndexError: list index out of range
>>> 

Python 中,用try except else語句塊捕獲並處理異常,其基本語法結構如下所示:

try:
    可能產生異常的代碼塊
except [ (Error1, Error2, ... ) [as e] ]:
    處理異常的代碼塊1
except [ (Error3, Error4, ... ) [as e] ]:
    處理異常的代碼塊2
except  [Exception]:
    處理其它異常
else:
    未發生異常

該格式中,[] 括起來的部分可以使用,也可以省略。其中各部分的含義如下:

  • (Error1, Error2,...) 、(Error3, Error4,...):其中,Error1、Error2、Error3 和 Error4 都是具體的異常類型。顯然,一個 except 塊可以同時處理多種異常。
  • [as e]:作為可選參數,表示給異常類型起一個別名 e,這樣做的好處是方便在 except 塊中調用異常類型(后續會用到)。
  • [Exception]:作為可選參數,可以代指程序可能發生的所有異常情況,其通常用在最后一個 except 塊。

try except else的基本語法格式可以看出,try 塊有且僅有一個,但 except 代碼塊可以有多個,且每個 except 塊都可以同時處理多種異常。

當程序發生不同的意外情況時,會對應特定的異常類型,Python 解釋器會根據該異常類型選擇對應的 except 塊來處理該異常。

try except else 語句的執行流程如下:

  1. 首先執行 try 中的代碼塊,如果執行過程中出現異常,系統會自動生成一個異常類型,並將該異常提交給 Python 解釋器,此過程稱為捕獲異常
  2. 當 Python 解釋器收到異常對象時,會尋找能處理該異常對象的 except 塊,如果找到合適的 except 塊,則把該異常對象交給該 except 塊處理,這個過程被稱為處理異常。如果在try后的語句里發生了異常,卻沒有匹配的except子句,異常將被遞交到上層的try,或者到程序的最上層(這樣將結束程序,並打印缺省的出錯信息)
  3. 如果在try子句執行時沒有發生異常,python將執行else語句后的語句(如果有else的話),然后控制流通過整個try語句


事實上,不管程序代碼塊是否處於 try 塊中,甚至包括 except 塊中的代碼,只要執行該代碼塊時出現了異常,系統都會自動生成對應類型的異常。但是,如果此段程序沒有用 try 包裹,又或者沒有為該異常配置處理它的 except 塊,則 Python 解釋器將無法處理,程序就會停止運行;反之,如果程序發生的異常經 try 捕獲並由 except 處理完成,則程序可以繼續執行。

示例(1):代碼運行正常

try:
    a = int(input("輸入被除數:"))
    b = int(input("輸入除數:"))
    c = a / b
    print("您輸入的兩個數相除的結果是:", c )
except (ValueError, ArithmeticError):
    print("程序發生了數字格式異常、算術異常之一")
except :
    print("未知異常")
else:
    print("未發生異常")
print("程序繼續運行")
        

運行結果:

輸入被除數:9
輸入除數:3
您輸入的兩個數相除的結果是: 3.0
未發生異常
程序繼續運行

示例(2)代碼運行失敗

輸入被除數:a
程序發生了數字格式異常、算術異常之一
程序繼續運行
>>> 

上面程序中,第 6 行代碼使用了(ValueError, ArithmeticError)來指定所捕獲的異常類型,這就表明該 except 塊可以同時捕獲這 2 種類型的異常;第 8 行代碼只有 except 關鍵字,並未指定具體要捕獲的異常類型,這種省略異常類的 except 語句也是合法的,它表示可捕獲所有類型的異常,一般會作為異常捕獲的最后一個 except 塊,但這不是一個很好的方式,我們不能通過該程序識別出具體的異常信息

除此之外,由於 try 塊中引發了異常,並被 except 塊成功捕獲,因此程序才可以繼續執行,才有了“程序繼續運行”的輸出結果。

獲取特定異常的有關信息

通過前面的學習,我們已經可以捕獲程序中可能發生的異常,並對其進行處理。但是,由於一個 except 可以同時處理多個異常,那么我們如何知道當前處理的到底是哪種異常呢?

其實,每種異常類型都提供了如下幾個屬性和方法,通過調用它們,就可以獲取當前處理異常類型的相關信息:

     1)args:返回異常的錯誤編號和描述字符串;

      2)str(e):返回異常信息,但不包括異常信息的類型;

      3)repr(e):返回較全的異常信息,包括異常信息的類型

try:
    1/0
except Exception as e:
    # 訪問異常的錯誤編號和詳細信息
    print(e.args)
    print(str(e))
    print(repr(e))

輸出結果為:

('division by zero',)
division by zero
ZeroDivisionError('division by zero',)
除此之外,如果想要更加詳細的異常信息,可以使用 traceback 模塊。有興趣的讀者,可自行查閱資料學習

從程序中可以看到,由於 except 可能接收多種異常,因此為了操作方便,可以直接給每一個進入到此 except 塊的異常,起一個統一的別名 e。

 

python中的try/except/else/finally語句

與其他語言相同,在python中,try/except語句主要是用於處理程序正常執行過程中出現的一些異常情況,如語法錯誤(python作為腳本語言沒有編譯的環節,在執行過程中對語法進行檢測,出錯后發出異常消息)、數據除零錯誤、從未定義的變量上取值等;

Python 異常處理機制還提供了一個 finally 語句,通常用來為 try 塊中的程序做掃尾清理工作。如在通信過程中,無論通信是否發生錯誤,都需要在通信完成或者發生錯誤時關閉網絡連接。

 

注意,和 else 語句不同,finally 只要求和 try 搭配使用,而至於該結構中是否包含 except 以及 else,對於 finally 不是必須的(else 必須和 try except 搭配使用)。

 在整個異常處理機制中,finally 語句的功能是:無論 try 塊是否發生異常,最終都要進入 finally 語句,並執行其中的代碼塊。

基於 finally 語句的這種特性,在某些情況下,當 try 塊中的程序打開了一些物理資源(文件、數據庫連接等)時,由於這些資源必須手動回收,而回收工作通常就放在 finally 塊中。

Python 垃圾回收機制,只能幫我們回收變量、類對象占用的內存,而無法自動完成類似關閉文件、數據庫連接等這些的工作。

讀者可能會問,回收這些物理資源,必須使用 finally 塊嗎?當然不是,但使用 finally 塊是比較好的選擇。首先,try 塊不適合做資源回收工作,因為一旦 try 塊中的某行代碼發生異常,則其后續的代碼將不會得到執行;其次 except 和 else 也不適合,它們都可能不會得到執行。而 finally 塊中的代碼,無論 try 塊是否發生異常,該塊中的代碼都會被執行。

默認情況下,在程序段的執行過程中,如果沒有提供try/except的處理,腳本文件執行過程中所產生的異常消息會自動發送給程序調用端,如python shell,而python shell對異常消息的默認處理則是終止程序的執行並打印具體的出錯信息。這也是在python shell中執行程序錯誤后所出現的出錯打印信息的由來。盡管try/except和try/finally的作用不同,但是在編程實踐中通常可以把它們組合在一起使用try/except/else/finally的形式來實現穩定性和靈活性更好的設計。
 
python中try/except/else/finally語句的完整格式如下所示:
try:
     Normal execution block
except A:
     Exception A handle
except B:
     Exception B handle
except:
     Other exception handle
else:
     if no exception,get here
finally:
     print("finally")   
說明:
正常執行的程序在try下面的Normal execution block執行塊中執行,在執行過程中如果發生了異常,則中斷當前在Normal execution block中的執行跳轉到對應的異常處理塊中開始執行;
python從第一個except X處開始查找,如果找到了對應的exception類型則進入其提供的exception handle中進行處理,如果沒有找到則直接進入except塊處進行處理。except塊是可選項,如果沒有提供,該exception將會被提交給python進行默認處理,處理方式則是終止應用程序並打印提示信息;
如果在Normal execution block執行塊中執行過程中沒有發生任何異常,則在執行完Normal execution block后會進入else執行塊中(如果存在的話)執行。
無論是否發生了異常,只要提供了finally語句,以上try/except/else/finally代碼塊執行的最后一步總是執行finally所對應的代碼塊。
需要注意的是:
1.在上面所示的完整語句中try/except/else/finally所出現的順序必須是try-->except X-->except-->else-->finally,即所有的except必須在else和finally之前,else(如果有的話)必須在finally之前,而except X必須在except之前。否則會出現語法錯誤。
2.對於上面所展示的try/except完整格式而言,else和finally都是可選的,而不是必須的,但是如果存在的話else必須在finally之前,finally(如果存在的話)必須在整個語句的最后位置。
3.在上面的完整語句中,else語句的存在必須以except X或者except語句為前提,如果在沒有except語句的try block中使用else語句會引發語法錯誤。也就是說else不能與try/finally配合使用。
4.except的使用要非常小心,慎用。
class AError(Exception):
     """AError---exception"""
     print('AError')
 
try:
     #raise AError
     asdas('123')
except AError:
     print("Get AError")
except:
     print("exception")     
else:
     print("else")
finally:
     print("finally")     
print("hello wolrd")
在上面的代碼中,Normal execution block中出現了語法錯誤,但是由於使用了except語句,該語法錯誤就被掩蓋掉了。因此在使用try/except是最好還是要非常清楚的知道Normal execution block中有可能出現的異常類型以進行針對性的處理。
 
try:
    a = int(input("請輸入 a 的值:"))
    print(20/a)
except:
    print("發生異常!")
else:
    print("執行 else 塊中的代碼")   
finally :
    print("執行 finally 塊中的代碼")

運行此程序:

請輸入 a 的值:4
5.0
執行 else 塊中的代碼
執行 finally 塊中的代碼

可以看到,當 try 塊中代碼為發生異常時,except 塊不會執行,else 塊和 finally 塊中的代碼會被執行。

再次運行程序:

請輸入 a 的值:a
發生異常!
執行 finally 塊中的代碼

可以看到,當 try 塊中代碼發生異常時,except 塊得到執行,而 else 塊中的代碼將不執行,finally 塊中的代碼仍然會被執行。

finally 塊的強大還遠不止此,即便當 try 塊發生異常,且沒有合適和 except 處理異常時,finally 塊中的代碼也會得到執行。例

try:
    #發生異常
    print(20/0)
finally :
    print("執行 finally 塊中的代碼")

程序執行結果為:

執行 finally 塊中的代碼
Traceback (most recent call last):
  File "D:\python3.6\1.py", line 3, in <module>
    print(20/0)
ZeroDivisionError: division by zero

可以看到,當 try 塊中代碼發生異常,導致程序崩潰時,在崩潰前 Python 解釋器也會執行 finally 塊中的代碼。

Python中關於try...finally的一些疑問

以“Open-Read-Write"文件為例,執行操作中,當某流程執行失敗時,都要先Close文件后再返回相關內容。如果操作流程多,每個步驟都要寫上close函數,這樣會出現漏寫的情況

      

 

以try-except-else-finally。的好處是避免了頻繁寫close函數、

先以代碼引入

def func(x):
    try:
        return ++x
    finally:
        return x+1

func(11)
你覺得是幾?

看到問題,覺得肯定是12啊

下邊看看我寫的例子,就明白其中的問題了。

示例1

def f():
    try:
        print(1)
        return 1
    finally:
        print(0)
        return 0

f()
結果為 1 0 0
以運行結果為准,說明無論try里執行什么,即使是return,也會調用finally的。
但是有一個問題,為什么最后輸出的不是1而是0呢?明明try里面已經返回1了!

def f():
    try:
        print(1)
        return 1
    finally:
        print(0)
        #return 0

將finally的return屏蔽掉,你或許猜到結果了

結果為 1 0 1

詫異嗎?

對比上個結果,說明try的返回值被finally的返回值覆蓋了,或許是因為一個函數只能有一個返回值,以最后一個結果為准

由此我想再驗證下else的情況,如下:

def f():
    try:
        print(1)
        return 1
    except:
        return 2
    else:
        print(3)
        return 3
    finally:
        print(0)
        #return 0

你覺得,沒有異常else會執行嗎?

如你所料,並沒有執行。

結果為 1 0 1

說明try里面運行完之后return,阻擋了else的執行,但是並沒有影響finally的執行。

 

借用Vamer文章的兩句話:

“如果try中沒有異常,那么except部分將跳過,執行else中的語句。

finally是無論是否有異常,最后都要做的一些事情。”

這里補充一句,在含有return的情況下,並不會阻礙finally的執行。


免責聲明!

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



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