【Python學習】python學習手冊--第三十三章 異常編碼細節

try/except/else語句

try其實是複合語句,try語句最完整的形式如下:

try:
    <statements>  #代碼主模塊
except <name1>:   #當產生<name1>異常的時候執行代碼塊<statements1>
    <statements1>
except (<name2>,<name3>):   #當產生<name2>,<name3>異常的時候執行代碼塊<statements2>
    <statements2>
except <name4> as <data>:   #產生<name4>異常時,將<name4>異常作爲實例<data>傳入
    <statements4>
except:                     #產生沒有包含以上幾個異常的其他異常時,執行<statements5>
    <statements5>
else:                       #沒有異常發生時,執行statements6
    <statements6>

try語句下的代碼爲程序的主要動作,在except子句下面的語句是各個異常相應的處理器,而else語句(可選)則是提供沒有異常發生時要執行的處理器 。這裏的”< data >”語句與rasie語句有關,稍後進行說明。
try語句執行代碼處理流程如下:

  • 先執行try語句下的主要動作代碼,如果有異常發生,就會跳出try語句塊,並在except子語句中找到第一個符合引發異常的代碼塊,處理完成後,就會跳過try語句塊中的剩下語句,按照順序執行整個try後的語句。
  • 如果發生了異常,但是並沒有找到合適的處理該異常的處理器,異常就會被Python程序默認處理(終止程序運行,並打印出相關異常信息)。
  • 如果try語句中的主要動作沒有發生相關異常,Python就會執行else語句,執行完成後,繼續執行後面的Python語句。

總之,except子句是專注於處理異常,當try語句下沒有發生異常時,纔會去執行else子句下的代碼。從語法上講,except從句沒有數量限制,然而一個try語句只能有一個else語句以及一個finally語句。分句的形式總結如下表格:

分句形式 說明
except: 捕捉所有(其它)異常,一般出現在except分句的最後一個
except name: 捕捉特定異常
except name,value: 捕捉異常和其它額外的數據(或實例)
except (name1,name2): 捕捉元組中列出的任何異常
except (name1,name2),value: 捕捉列出的任何異常,並獲取額外的數據
else: 如果沒有異常發生,就運行該模塊
finally: 無論有沒有異常發生,總是會運行此模塊代碼

except: 分句形式是一種通用功能可以捕捉一切異常,在Python中即便是系統離開調用,也會觸發異常,而你通常會讓這些事通過,在Python3.0中可以使用 except Exception:來替代這種通用功能,這與它有相同功能,但是會忽略和系統退出的相關異常。
else語句一般都是放在try代碼塊中,但是如果知道else分句,會使你的try語句邏輯更加清晰。因爲你的代碼放在try語句中也有可能發生一些異常。

try/finally語句

try:
   <statements1>
finally:
   <statements2>

首先執行try語句下的代碼,如果沒有異常發生,也會執行finally語句。然後再繼續執行整個try語句之後的語句。
而如果發生了異常,依然會執行finally代碼塊。但是接着會把異常信息向上層傳遞到較高的try語句或頂層默認器,程序不會繼續執行try語句後的語句。在Python2.5之後,finally語句可以和try語句的其它分句一起使用,一般都用它來指明一定要執行的“清理”動作(比如服務器斷開,文件關閉等),無論異常發生了沒有。

finally語句與except分句不一樣,finally語句不會攔截異常而是傳遞異常。如果異常沒有在except分句中被攔截,那麼就會由默認異常處理器處理(執行完finally分句中的內容後,終止程序運行,並輸出異常)

統一try語句語法

try語句必須有一個except或一個finally語法,並且其部分的順序必須如下:
try -> except -> else -> finally
其中else和finally是可選的,可能會有0個或多個except,但是如果出現一個else的話,必須有至少一個except。總的說來try語句可以有兩個部分,一個是帶有else(可選的)的except語句,或者帶有finally語句

raise語句

raise語句通常用來顯式地觸發異常,通常有以下幾種方法:

raise <instance>  # 拋出一個異常實例
raise <class>     # 拋出一個異常類(異常狀態),其效果相當於在類名後加圓括號。
raise             # 最後的形式重新引發最近引發的異常。通常用在異常處理器中,用於傳播已補貨的異常

異常鏈:raise from語句

當使用 raise exception from otherexception時,第二個表達式指定了另一個異常類或實例,它會附加到前一個異常的__cause__屬性中。

>>> raise TypeError('Bad!') from Exception
Exception

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Bad!
>>>

assert語句

assert語句可以通過條件判斷來拋出AssertionError異常。
assert [test],[data]
這個語句執行的效果就像:

if test:
    raise AssertioanError([data])

可以使用類似python -0 mani.py 的命令來讓python程序中用優化模式運行,並且關閉assert語句。
assert語句通常是用於驗證開發期間程序狀況的

with語句

基本格式如下:

with expression as [variable]:
     <with-block statements>

with語句會用expression返回的支持環境管理協議的對象,賦值給as後面的variable變量。在運行with-block中的語句後終止環境管理協議的對象(比如關閉文件等)。

環境管理協議

要實現一個環境管理器,使得該對象可以接入with語句,該方法屬於運算符重載的範疇。
以下是with語句實際的工作方式:

  • with表達式所得到得對象爲環境管理器,它必須有__enter__和__exit__方法。
  • 在with語句開始時,enter方法會被調用,如果存在as子語句,那麼返回值會賦值給as子語句後面的變量名,否則直接丟棄
  • 嵌套在with語句中代碼就會執行
  • 如果with內的語句發生了異常,則會將相關參數傳到__exit__方法。如果此方法返回值爲假,則異常會重新引發。否則異常會終止。正常情況下,異常時應該被重新引發,這樣的話才能傳遞到with語句之外。
  • 如果with內的語句沒有異常發生,__exit__方法依然會被調用,但是參數都是以None傳遞。
>>> class TraceBlock:
...     def message(self,arg):
...         print('running', arg)
...     def __enter__(self):
...         print("starting enter block")
...         return self
...     def __exit__(self,exc_type,exc_value,exc_tb):
...         print("starting exit block")
...         print(exc_type,exc_value,exc_tb)
...         if exc_type is None:
...             print('exited normally')
...         else:
...             print("raise an exception", exc_type)
...             return False
... 
>>> with TraceBlock() as lxm:  
...     lxm.message("testtest")
... 
starting enter block
running testtest
starting exit block
None None None
exited normally
>>> 
>>> with TraceBlock() as lxm:  
...     lxm.message("testtest")
...     raise TypeError
... 
starting enter block
running testtest
starting exit block
<class 'TypeError'>  <traceback object at 0x7ff163181c48>
raise an exception <class 'TypeError'>
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError
>>> 

以上例子可以看出,環境管理器會以__enter__和__exit__跟蹤with語句代碼塊的進入和離開。
在python3.1的版本中,可以在一個with語句中直接使用兩個環境管理器:

with open("data") as fin, open("res",'w') as fout:
   <statements>

當with語句運行完成後,這兩個環境管理器都會退出。

小結

異常管理編碼有幾個語句,try是標識需要捕捉異常的主程序,except是捕捉各類異常,raise是觸發異常,assert是條件式引發異常,而with是把代碼塊包裝在環境管理器中(定義了__enter__和__exit__方法。)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章