生活随笔
收集整理的這篇文章主要介紹了
python with方法
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
閱讀目錄
在實(shí)際的編碼過程中,有時(shí)有一些任務(wù),需要事先做一些設(shè)置,事后做一些清理,這時(shí)就需要python with出場(chǎng)了,with能夠?qū)@樣的需求進(jìn)行一個(gè)比較優(yōu)雅的處理,最常用的例子就是對(duì)訪問文件的處理。
一般訪問文件資源時(shí)我們會(huì)這樣處理:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
注:如果你對(duì)python感興趣,我這有個(gè)學(xué)習(xí)Python基地,里面有很多學(xué)習(xí)資料,感興趣的
+ Q群:
895817687
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - f
= open ( r
'c:\test.txt' , 'r' )
data
= f
. read
( )
f
. close
( )
這樣寫沒有錯(cuò),但是容易犯兩個(gè)毛病:
如果在讀寫時(shí)出現(xiàn)異常而忘了異常處理。 忘了關(guān)閉文件句柄
以下的加強(qiáng)版本的寫法:
f
= open ( r
'c:\test.txt' , 'r' ) try : data
= f
. read
( ) finally : f
. close
( )
以上的寫法就可以避免因讀取文件時(shí)異常的發(fā)生而沒有關(guān)閉問題的處理了。代碼長(zhǎng)了一些。 但使用with有更優(yōu)雅的寫法:
with open ( r
'c:\test.txt' , 'r' ) as f
: data
= f
. read
( )
說明: with后面接的對(duì)象返回的結(jié)果賦值給f。此例當(dāng)中open函數(shù)返回的文件對(duì)象賦值給了f.with會(huì)自已獲取上下文件的異常信息。 with是如何做到的呢? with后面返回的對(duì)象要求必須兩__enter__()/exit ()這兩個(gè)方法,而文件對(duì)象f剛好是有這兩個(gè)方法的,故應(yīng)用自如。 pytho中官方定義說明如下(https://docs.python.org/2/reference/datamodel.html#context-managers):
object . __enter__
( self
)
進(jìn)入與此對(duì)象相關(guān)的運(yùn)行時(shí)上下文。
with 語(yǔ)句將將此方法的返回值綁定到語(yǔ)句的AS子句中指定的目標(biāo)(如果有設(shè)置的話)
object . __exit__
( self
, exc_type
, exc_value
, traceback
)
退出與此對(duì)象相關(guān)的運(yùn)行時(shí)上下文。參數(shù)描述導(dǎo)致上下文退出的異常。如果上下文運(yùn)行時(shí)沒有異常發(fā)生,那么三個(gè)參數(shù)都將置為
None 。
如果有異常發(fā)生,并且該方法希望抑制異常(即阻止它被傳播),則它應(yīng)該返回
True 。否則,異常將在退出該方法時(shí)正常處理。請(qǐng)注意
, __exit__
( ) 方法不應(yīng)該重新拋出傳入的異常,這是調(diào)用者的職責(zé)。
所謂上下文管理協(xié)議,就是咱們打開文件時(shí)常用的一種方法:with
enter (self):當(dāng)with開始運(yùn)行的時(shí)候觸發(fā)此方法的運(yùn)行
exit (self, exc_type, exc_val, exc_tb):當(dāng)with運(yùn)行結(jié)束之后觸發(fā)此方法的運(yùn)行
exc_type如果拋出異常,這里獲取異常的類型
exc_val如果拋出異常,這里顯示異常內(nèi)容
exc_tb如果拋出異常,這里顯示所在位置
下面舉例說明他的原理:
無異常發(fā)生時(shí)的例子:
class Test : def __enter__ ( self
) : print ( '__enter__() is call!' ) return self
def dosomething ( self
) : print ( 'dosomethong!' ) def __exit__ ( self
, exc_type
, exc_value
, traceback
) : print ( '__exit__() is call!' ) print ( f
'type:{exc_type}' ) print ( f
'value:{exc_value}' ) print ( f
'trace:{traceback}' ) print ( '__exit()__ is call!' ) with Test
( ) as sample
: sample
. dosomething
( ) >>
__enter__
( ) is call!
dosomethong!
__exit__
( ) is call!
type : None
value
: None
trace
: None
__exit
( ) __
is call!
以上的實(shí)例Text,我們注意到他帶有__enter__()/exit ()這兩個(gè)方法,當(dāng)對(duì)象被實(shí)例化時(shí),就會(huì)主動(dòng)調(diào)用__enter__()方法,任務(wù)執(zhí)行完成后就會(huì)調(diào)用__exit__()方法,另外,注意到,exit ()方法是帶有三個(gè)參數(shù)的(exc_type, exc_value, traceback), 依據(jù)上面的官方說明:如果上下文運(yùn)行時(shí)沒有異常發(fā)生,那么三個(gè)參數(shù)都將置為None, 這里三個(gè)參數(shù)由于沒有發(fā)生異常,的確是置為了None, 與預(yù)期一致.
有異常發(fā)生時(shí),會(huì)拋出異常的例子: 以下例子在上面稍做了一些修改,讓運(yùn)行時(shí)產(chǎn)生異常,看看這三個(gè)參數(shù)的賦值情況:
class Test : def __enter__ ( self
) : print ( '__enter__() is call!' ) return self
def dosomething ( self
) : x
= 1 / 0 print ( 'dosomethong!' ) def __exit__ ( self
, exc_type
, exc_value
, traceback
) : print ( '__exit__() is call!' ) print ( f
'type:{exc_type}' ) print ( f
'value:{exc_value}' ) print ( f
'trace:{traceback}' ) print ( '__exit()__ is call!' ) with Test
( ) as sample
: sample
. dosomething
( )
>>
__enter__
( ) is call!
Traceback
( most recent call last
) :
__exit__
( ) is call!
type : < class 'ZeroDivisionError' > File
"C:/Users/xxx/PycharmProjects/Test1/test.py" , line
23 , in < module
>
value
: division by zerosample
. dosomething
( )
trace
: < traceback
object at
0x000001C08CF32F88 > File
"C:/Users/xxx/PycharmProjects/Test1/test.py" , line
10 , in dosomething
__exit
( ) __
is call!x
= 1 / 0
ZeroDivisionError
: division by zero
從結(jié)果可以看出, 在執(zhí)行到dosomethong時(shí)就發(fā)生了異常,然后將異常傳給了__exit__(), 依據(jù)上面的官方說明:如果有異常發(fā)生,并且該方法希望抑制異常(即阻止它被傳播),則它應(yīng)該返回True。否則,異常將在退出該方法時(shí)正常處理。當(dāng)前__exit__并沒有寫明返回True,故會(huì)拋出異常,也是合理的,但是正常來講,程序應(yīng)該是不希望它拋出異常的,這也是調(diào)用者的職責(zé),我們將再次修改__exit__, 將其返回設(shè)置為True,
有異常發(fā)生時(shí),不再拋出異常的例子:
class Test : def __enter__ ( self
) : print ( '__enter__() is call!' ) return self
def dosomething ( self
) : x
= 1 / 0 print ( 'dosomethong!' ) def __exit__ ( self
, exc_type
, exc_value
, traceback
) : print ( '__exit__() is call!' ) print ( f
'type:{exc_type}' ) print ( f
'value:{exc_value}' ) print ( f
'trace:{traceback}' ) print ( '__exit()__ is call!' ) return True with Test
( ) as sample
: sample
. dosomething
( ) >>
__enter__
( ) is call!
__exit__
( ) is call!
type : < class 'ZeroDivisionError' >
value
: division by zero
trace
: < traceback
object at
0x000001C94E592F88 >
__exit
( ) __
is call!
從結(jié)果看,異常拋出被抑制了,符合預(yù)期。
總結(jié)
以上是生活随笔 為你收集整理的python with方法 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。