先說明乙個常見問題,檔案開啟:
try:
f = open('***')
do something
except:
do something
finally:
f.close()
其實我個人不止一次在網上看到有這麼寫的了,這個是錯的。
首先正確的如下:
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
的語法結構:
set things 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
得工作沒有完全執行。
也就是說with
是乙個控制流語句,跟if/for/while/try
之類的是一類的,with
可以用來簡化try finally
**,看起來可以比try finally
更清晰。
這裡新引入了乙個」上下文管理協議"context management protocol"
,實現方法是為乙個類定義__enter__
和__exit__
兩個函式。
with expresion as variable
的執行過程是,首先執行__enter__
函式,它的返回值會賦給as
後面的variable
,想讓它返回什麼就返回什麼,只要你知道怎麼處理就可以了,如果不寫as variable
,返回值會被忽略。
然後,開始執行with-block
中的語句,不論成功失敗(比如發生異常、錯誤,設定sys.exit()
),在with-block
執行完成後,會執行__exit__
函式。
這樣的過程其實等價於:
try:
執行 __enter__的內容
執行 with_block.
finally:
執行 __exit__內容
最終的python-dev
團隊的解決方案。(python 2.5
以後增加了with
表示式的語法)
class
controlled_execution:
def__enter__
(self):
set things up
return thing
def__exit__
(self, type, value, traceback):
tear things down
with controlled_execution() as thing:
do something
只不過,現在把一部分**封裝成了__enter__
函式,清理**封裝成__exit__
函式。
我們可以自己實現乙個例子:
import sys
class
test:
def__enter__
(self):
print("enter")
return
1def
__exit__
(self,*args):
print("exit")
return
true
with test() as t:
print("t is not the result of test(), it is __enter__ returned")
print("t is 1, yes, it is ".format(t))
raise nameerror("hi there")
sys.exit()
print("never here")
在這裡,python
使用了with-as
的語法。當python
執行這一句時,會呼叫__enter__
函式,然後把該函式return
的值傳給as
後指定的變數。之後,python
會執行下面do something
的語句塊。最後不論在該語句塊出現了什麼異常,都會在離開時執行__exit__
。
另外,__exit__
除了用於tear things down
,還可以進行異常的監控和處理,注意後幾個引數。要跳過乙個異常,只需要返回該函式true
即可。下面的樣例**跳過了所有的typeerror
,而讓其他異常正常丟擲。
def
__exit__
(self, type, value, traceback):
return isinstance(value, typeerror)
在python2.5
及以後,file
物件已經寫好了__enter__
和__exit__
函式,我們可以這樣測試:
>>> f = open("x.txt")
>>> f
file
'x.txt', mode 'r'
at0x00ae82f0>
>>> f.__enter__()
file
'x.txt', mode 'r'
at0x00ae82f0>
>>> 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
之後,我們如果要開啟檔案並保證最後關閉他,只需要這麼做:
with open("x.txt") as f:
data = f.read()
do something with data
如果有多個項,我們可以這麼寫:
with
open("x.txt") as f1, open('***.txt') as f2:
do something with f1,f2
上文說了__exit__
函式可以進行部分異常的處理,如果我們不在這個函式中處理異常,他會正常丟擲,這時候我們可以這樣寫(python 2.7
及以上版本,之前的版本參考使用contextlib.nested
這個庫函式):
try:
with
open( "a.txt" ) as f :
do something
except ***error:
do something about exception
總之,with-as
表示式極大的簡化了每次寫finally
的工作,這對保持**的優雅性是有極大幫助的。 Python中with語句的理解
with expr as var block 簡單說明 1,expr可以是任意表示式。2,as var是可選的。3,block是with語句的語句體1,計算expr,並獲取乙個上下文管理器。2,上下文管理器的exit 方法被儲存起來用於之後的呼叫。3,呼叫上下文管理器的enter 方法 4,如果wi...
Python中類的理解
x,y本身沒有setdata屬性,python會順著類的連線搜尋,也就是python的繼承,繼承在屬性點號運算時發生的,只於查詢連線物件內的變數名有關。以上 例子中的x.setdata aaa 會傳入self.data中。因為類會產生多個例項,所以必須經過self引數才能獲取正在處理的例項。因為se...
理解Python中的鎖
一 全域性直譯器鎖 global interpreter lock,gil 1.什麼是全域性直譯器鎖 2.全域性直譯器鎖的好處 3.全域性直譯器鎖的缺點 import time import threading defsub global num num 1 time.sleep 1 num 100...