使用上下文管理協議,有什麼好處?python
使用with語句的目的就是把代碼塊放入with中執行,with結束後,自動完成清理工做,無須手動干預。編程
在須要管理一些資源好比文件,網絡鏈接和鎖的編程環境中,能夠在__exit__中定製自動釋放資源的機制,你無須再去關係這個問題,這將大有用處。
網絡
以前所提到的with代碼塊,就是python的上下文管理操做,好比說經過python打開一個文件,就能夠經過with代碼塊結合open去實現,經過這種方式打開的文件,執行了相應的操做後,無需咱們手動去close文件,文件就會自動關閉。ide
好比:spa
with open('a.txt') as f:對象
'代碼塊'ci
#上面這個例子,就是一個上下文管理協議,即with語句,爲了讓一個對象能夠去兼容with語句,則必須在這個對象的類中,去聲明__enter__和__exit__方法。資源
這種上下文的管理,就是經過類中的__enter__和__exit__這兩個內置方法去實現的。it
下面是__enter__和__exit__的用法示例:class
class test:
def __init__(self,name):
self.name = name
def __enter__(self):
#print "只要with語句一出現,這個對象的__enter__方法就會被觸發,__enter__這個方法的返回值會賦值給as 後面聲明的變量"
print "我是__enter__方法,with出現時就會執行我~"
def __exit__(self, exc_type, exc_val, exc_tb):
print "我是__exit__方法,__enter__執行完畢會執行我"
with test(123) as t1:
print "aaaa"
咱們來看看輸出結果:
我是__enter__方法,with出現時就會執行我~
aaaa
我是__exit__方法,__enter__執行完畢會執行我
#__exit__()中的三個參數分別表明異常類型,異常值和追溯信息,with語句中代碼塊出現異常,則with後的代碼都沒法執行。
#傳入__exit__方法中的exc_type,exc_val,exc_tb,分別是(異常類,異常的值,追蹤信息)這三個參數只有當__enter__方法或者with下的代碼塊下的代碼出現異常,這三個參數纔會有值,不然就是三個None。
#__exit__()中的三個參數分別表明異常類型,異常值和追溯信息,with語句中代碼塊出現異常,則with後的代碼都沒法執行,直接開始執行__exit__方法。
關於上下文管理的異常處理:
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出現with語句,對象的__enter__被觸發,有返回值則賦值給as聲明的變量')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代碼塊執行完畢時執行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
with Open('a.txt') as f:
print('=====>執行代碼塊')
raise AttributeError('***着火啦,救火啊***')
print('0'*100) #------------------------------->不會執行
從上面這個例子能夠看出來,當with的代碼塊的執行出現異常的時候,python會直接開始執行對象的__exit__方法,當__exit__內的方法也執行完畢,整個程序就終止掉了。
那麼,如何處理with代碼塊中的異常呢?
注意看下面這個例子!!
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出現with語句,對象的__enter__被觸發,有返回值則賦值給as聲明的變量')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代碼塊執行完畢時執行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
return True #注意這裏!!!!
with Open('a.txt') as f:
print('=====>執行代碼塊')
raise AttributeError('***着火啦,救火啊***')
print('0'*100) #------------------------------->會執行
當__exit__方法,返回的爲值True時,就好像啥都沒發生同樣,with後的語句正常執行,with代碼塊中的異常被屏蔽掉了!!
最後關於python的上下文管理,作一個總結:
在沒有任何異常的狀況下,整個代碼塊的內容運行完畢後會去觸發對象的__exit__方法,它的三個參數都爲None。
當有異常存在的狀況下,從異常位置,直接觸發__exit__。
2.1 當手動將__exit__方法的返回值修改成True,with語句就會屏蔽掉異常。
2.2 當__exit__的返回值不爲True,在with代碼塊中遇到異常就會拋出。
2.3 當__exit__這個方法一旦運行完畢,就表明了整個with語句執行完畢。