Python中的with as 語法

2021-07-12 03:25:54 字數 4155 閱讀 9560

使用語言的好特性,而不是那些糟糕的特性————不知道誰說的

好久不學習python的語法了,上次去面試,和面試官聊到了python中的with-as statement(也稱context manager),挺感興趣的,這兩天學習了一番,收穫頗豐在此分享。

先說明乙個常見問題,檔案開啟: 1

2 34 5

6 7try:

f =open

('***')

do something

except:

do something

finally:

f.close()

其實我個人不止一次在網上看到有這麼寫的了,這個是錯的。

首先正確的如下: 1

2 34 5

6 78 9

10 11

try:

f =open

('***'

) except:

print

'fail to open'

exit(-1

) try:

do something

except:

do something

finally:

f.close()

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

我們為什麼要寫finally,是因為防止程式丟擲異常最後不能關閉檔案,但是需要關閉檔案有乙個前提就是檔案已經開啟了。

在第一段錯誤**中,如果異常發生在f=open(『***』)的時候,比如檔案不存在,立馬就可以知道執行f.close()是沒有意義的。改正後的解決方案就是第二段**。

好了言歸正轉,開始討論with語法。

首先我們從下面這個問題談起,try-finally的語法結構: 1

2 34 5

setthings up

try:

do something

finally:

tear things down

這東西是個常見結構,比如檔案開啟,

set things up

就表示f=open('***')

,tear things down

就表示f.close()

。在比如像多執行緒鎖,資源請求,最終都有乙個釋放的需求。try…finally結構保證了tear things down這一段永遠都會執行,即使上面do something得工作沒有完全執行。

如果經常用這種結構,我們首先可以採取乙個較為優雅的辦法,封裝! 1

2 34 5

6 78 9

10 11

defcontrolled_execution(callback):

setthings up

try:

callback(thing)

finally:

tear things down

defmy_function(thing):

do something

controlled_execution(my_function)

封裝是乙個支援**重用的好辦法,但是這個辦法很dirty,特別是當do something中有修改一些local variables的時候(變成函式呼叫,少不了帶來變數作用域上的麻煩)。

另乙個辦法是使用生成器,但是只需要生成一次資料,我們用for-in結構去呼叫他: 1

2 34 5

6 78 9

defcontrolled_execution():

setthings up

try:

yield

thing

finally:

tear things down

forthing

incontrolled_execution():

do something with thing

因為thing只有乙個,所以yield語句只需要執行一次。當然,從**可讀性也就是優雅的角度來說這簡直是糟糕透了。我們在確定for迴圈只執行一次的情況下依然使用了for迴圈,這**給不知道的人看一定很難理解這裡的迴圈是什麼個道理。

最終的python-dev團隊的解決方案。(python 2.5以後增加了with表示式的語法) 1

2 34 5

6 78 9

class

controlled_execution:

def__enter__(

self):

setthings up

return

thing

def__exit__(

self

, type

, value, traceback):

tear things down

with controlled_execution() as thing:

do something

在這裡,python使用了with-as的語法。當python執行這一句時,會呼叫__enter__函式,然後把該函式return的值傳給as後指定的變數。之後,python會執行下面do something的語句塊。最後不論在該語句塊出現了什麼異常,都會在離開時執行__exit__。

另外,__exit__除了用於tear things down,還可以進行異常的監控和處理,注意後幾個引數。要跳過乙個異常,只需要返回該函式true即可。下面的樣例**跳過了所有的typeerror,而讓其他異常正常丟擲。 1

2 def__exit__(

self

, type

, value, traceback):

return

isinstance

(value, typeerror)

在python2.5及以後,file物件已經寫好了__enter__和__exit__函式,我們可以這樣測試: 1

2 34 5

6 78 9

10 11

12 >>> f

=open

("x.txt"

) >>> f

<

open

file

'x.txt'

, mode

'r'at

0x00ae82f0

>

>>> f.__enter__()

<

open

file

'x.txt'

, mode

'r'at

0x00ae82f0

>

>>> f.read(1)

'x'>>> f.__exit__(

none

, none

, none

) >>> f.read(1)

traceback (most recent call last):

file

"", line 1,

in valueerror: i

/o operation on closed

file

之後,我們如果要開啟檔案並保證最後關閉他,只需要這麼做: 1

2 3with

open

("x.txt"

) as f:

data

=f.read()

do something with data

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

2 with

open

("x.txt"

) as f1,

open

('***.txt'

) as f2:

do something with f1,f2

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

2 34 5

try:

with

open

( "a.txt"

) as f :

do something

except

***error:

do something about exception

總之,with-as表示式極大的簡化了每次寫finally的工作,這對保持**的優雅性是有極大幫助的。

python 中 with as的用法

with從python 2.5就有,需要from future import with statement。自python 2.6開始,成為預設關鍵字。在what s new in python2.6 3.0中,明確提到 the with statement is a control flow st...

Python中with as的用法

這個語法是用來代替傳統的try.finally語法的。with expression as variable with block 基本思想是with所求值的物件必須有乙個 enter 方法,乙個 exit 方法。緊跟with後面的語句被求值後,返回物件的 enter 方法被呼叫,這個方法的返回值將...

Python中的with as 語法

1 使用with.as.的原因 python操作檔案時,需要開啟檔案,最後手動關閉檔案。通過使用with.as.不用手動關閉檔案。當執行完內容後,自動關閉檔案。2 先說明乙個常見問題,檔案開啟 try f open do something except do something finally f...