Python中with...as...

先說明一個常見問題,文件打開:

try:? ? f =open('xxx')dosomethingexcept:dosomethingfinally:? ? f.close()

1

2

3

4

5

6

7

1

2

3

4

5

6

7

其實不止一次在網(wǎng)上看到有這么寫的了,這個是錯的。

首先正確的如下:

try:? ? f = open('xxx')except:? ? print'fail to open'exit(-1)try:dosomethingexcept:dosomethingfinally:? ? f.close()

1

2

3

4

5

6

7

8

9

10

11

1

2

3

4

5

6

7

8

9

10

11

很麻煩不是么,但正確的方法就是這么寫。

我們?yōu)槭裁匆獙慺inally,是因為防止程序拋出異常最后不能關(guān)閉文件,但是需要關(guān)閉文件有一個前提就是文件已經(jīng)打開了。

在第一段錯誤代碼中,如果異常發(fā)生在f=open(‘xxx’)的時候,比如文件不存在,立馬就可以知道執(zhí)行f.close()是沒有意義的。改正后的解決方案就是第二段代碼。

好了言歸正轉(zhuǎn),開始討論with語法。

首先我們從下面這個問題談起,try-finally的語法結(jié)構(gòu):

setthings uptry:dosomethingfinally:? ? tear things down

1

2

3

4

5

1

2

3

4

5

這東西是個常見結(jié)構(gòu),比如文件打開,set things up就表示f=open(‘xxx’),tear things

down就表示f.close()。在比如像多線程鎖,資源請求,最終都有一個釋放的需求。Try…finally結(jié)構(gòu)保證了tear things

down這一段永遠都會執(zhí)行,即使上面do something得工作沒有完全執(zhí)行。

如果經(jīng)常用這種結(jié)構(gòu),我們首先可以采取一個較為優(yōu)雅的辦法,封裝!

defcontrolled_execution(callback):set things uptry:? ? ? ? callback(thing)finally:? ? ? ? tear things downdefmy_function(thing):do somethingcontrolled_execution(my_function)

1

2

3

4

5

6

7

8

9

10

11

1

2

3

4

5

6

7

8

9

10

11

封裝是一個支持代碼重用的好辦法,但是這個辦法很dirty,特別是當do something中有修改一些local variables的時候(變成函數(shù)調(diào)用,少不了帶來變量作用域上的麻煩)。

另一個辦法是使用生成器,但是只需要生成一次數(shù)據(jù),我們用for-in結(jié)構(gòu)去調(diào)用他:

defcontrolled_execution():set things uptry:yieldthingfinally:? ? ? ? tear things downforthingincontrolled_execution():? ? do somethingwiththing

1

2

3

4

5

6

7

8

9

1

2

3

4

5

6

7

8

9

因為thing只有一個,所以yield語句只需要執(zhí)行一次。當然,從代碼可讀性也就是優(yōu)雅的角度來說這簡直是糟糕透了。我們在確定for循環(huán)只執(zhí)行一次的情況下依然使用了for循環(huán),這代碼給不知道的人看一定很難理解這里的循環(huán)是什么個道理。

最終的Python-dev團隊的解決方案。(python2.5以后增加了with表達式的語法)

classcontrolled_execution:def__enter__(self):set things upreturnthingdef__exit__(self, type, value, traceback):tear things downwithcontrolled_execution()asthing:? ? ? ? do something

1

2

3

4

5

6

7

8

9

1

2

3

4

5

6

7

8

9

在這里,python使用了with-as的語法。當python執(zhí)行這一句時,會調(diào)用__enter__函數(shù),然后把該函數(shù)return的值傳給as后指定的變量。之后,python會執(zhí)行下面do something的語句塊。最后不論在該語句塊出現(xiàn)了什么異常,都會在離開時執(zhí)行__exit__。

另外,__exit__除了用于tear things down,還可以進行異常的監(jiān)控和處理,注意后幾個參數(shù)。要跳過一個異常,只需要返回該函數(shù)True即可。下面的樣例代碼跳過了所有的TypeError,而讓其他異常正常拋出。

def__exit__(self, type, value, traceback):returnisinstance(value, TypeError)

1

2

1

2

在python2.5及以后,file對象已經(jīng)寫好了enterexit函數(shù),我們可以這樣測試

>>> f =open("x.txt")>>> f>>> f.__enter__()>>> f.read(1)'X'>>> f.__exit__(None, None, None)>>> f.read(1)Traceback (most recent calllast):? ? File"",line1,inValueError: I/O operationonclosedfile

1

2

3

4

5

6

7

8

9

10

11

12

1

2

3

4

5

6

7

8

9

10

11

12

之后,我們?nèi)绻蜷_文件并保證最后關(guān)閉他,只需要這么做:

withopen("x.txt")asf:data= f.read()dosomething withdata

1

2

3

1

2

3

如果有多個項,我們可以這么寫:

withopen("x.txt")asf1,open('xxx.txt')asf2:dosomethingwithf1,f2

1

2

1

2

上文說了__exit__函數(shù)可以進行部分異常的處理,如果我們不在這個函數(shù)中處理異常,他會正常拋出,這時候我們可以這樣寫(python 2.7及以上版本,之前的版本參考使用contextlib.nested這個庫函數(shù)):

try:withopen("a.txt")asf :dosomethingexcept xxxError:dosomething aboutexception

1

2

3

4

5

1

2

3

4

5

總之,with-as表達式極大的簡化了每次寫finally的工作,這對保持代碼的優(yōu)雅性是有極大幫助的。

with-block等價于

try:? ? ? ? 執(zhí)行 __enter__的內(nèi)容? ? ? ? 執(zhí)行 with_block.finally:? ? ? ? 執(zhí)行 __exit__內(nèi)容

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • Python’s with statement provides a very convenient way of...
    尼古拉斯_特侖蘇閱讀 490評論 0 1
  • 首先自黑,我之前一直用這種二逼寫法: 不僅粗魯,而且我們會發(fā)現(xiàn),在文件不存在的情況下,f.close()沒有意義。...
    李響同學閱讀 1,837評論 4 11
  • “你的,志雄君,有什么目標?”丁老師拍拍身邊日本籍學生秦川志雄的肩膀。 “認真完成作業(yè),還有,還有不給阿姨添麻煩。...
    幸福夢中仙閱讀 241評論 0 0
  • 這個題目本來是放假的時候我給,全校的學生布置的。因為在會議上我說了,讓每個班主任都給學生布置三篇作文,內(nèi)容就是春節(jié)...
    lygly9閱讀 314評論 0 1
  • 6-20星期一 今早鬧鐘響了兩遍才起來,明晃晃的【今天不去跑】的想法充斥著我的意識。我用幾乎就妥協(xié)了,最后戰(zhàn)勝這一...
    魏雨self閱讀 235評論 0 0

友情鏈接更多精彩內(nèi)容