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__方法。)