with語句支援在乙個叫上下文管理器的物件的控制下執行一系列語句,語法大概如下:
with context as var:
statements
其中的context必須是個上下文管理器,它實現了兩個方法__enter__,__exit__。
在正常的管理各種系統資源(檔案、鎖定和連線),在涉及到異常時通常是個棘手的問題。異常很可能導致控制流跳過負責釋放關鍵資源的語句。
看一段簡單的檔案寫入**:
filename = 'my_file.txt'
f = open(filename,'w')
f.write('hello ')
f.write('world')
f.close()
如果發生了意外的情況,例如寫入'world'時磁碟空間不足,就會丟擲異常,那麼close()語句將不會被執行。
一般的解決方案是使用try-finally語句:
try:
filename = 'my_file.txt'
f = open(filename,'w')
f.write('hello ')
f.write('world')
finally:
f.close()
但隨著語句的增多,try-finally顯然不夠簡潔,用with-as語句可以很簡潔的實現以上功能:
with open('my_file','w') as f:
f.write('hello ')
f.write('world')
這樣不僅能處理出現異常的情況,而且還避免了在open乙個檔案後忘記了寫close()方法的情況。
執行緒中的鎖其實也實現了上下文管理協議:
import threading
with threading.lock():
# 關鍵部分
statements
# 關鍵部分結束
再也不怕忘記將鎖釋放了。
上下文管理器要實現__enter__和__exit__的特殊方法。
__enter__(self): 進入上下文管理器時呼叫此方法,其返回值將被放入with-as語句中as說明符指定的變數中。
__exit__(self,type,value,tb):離開上下文管理器呼叫此方法。如果有異常出現,type、value、tb分別為異常的型別、值和追蹤資訊。如果沒有異常,
3個引數均設為none。此方法返回值為true或者false,分別指示被引發的異常得到了還是沒有得到處理。如果返回false,引發的異常會被傳遞出上下文。
檔案上下文管理協議大概是如下實現的:
class openfile(object):
def __init__(self,filename,mode):
self.filename=filename
self.mode=mode
def __enter__(self):
self.f=open(self.filename,self.mode)
return self.f #作為as說明符指定的變數的值
def __exit__(self,type,value,tb):
self.f.close()
return false #異常會被傳遞出上下文
with openfile('my_file.txt','w') as f:
f.write('hello ')
f.write('world')
相當於
try :
執行__enter__的內容
finally:
執行__exit__的內容
__exit__函式就能夠拿到關於異常的所有資訊(異常型別,異常值以及異常追蹤資訊),這些資訊將幫助異常處理操作。
class listtrans(object):
def __init__(self,alist):
self.alist=alist
def __enter__(self):
self.thecopy=list(self.alist)
return self.thecopy
def __exit__(self,exc_type,value,tb):
if exc_type is none:
self.alist[:]=self.thecopy
return false
沒有異常發生時:
alist=
with listtrans(alist) as working:
print alist
生成:
[1, 2]
有異常發生時:
alist=
with listtrans(alist) as working:
raise runtimeerror('we are hosed')
print alist
生成:
runtimeerror: we are hosed
alist無變化。
可以捕捉異常:
alist=
try:
with listtrans(alist) as working:
raise runtimeerror('we are hosed')
except runtimeerror as e:
print e
print alist
生成:
we are hosed
當然,也可以簡單的將__exit__的返回值設為true來忽略異常。
@contextmanager
contextlib模組的contextmanager裝飾器可以更方便的實現上下文管理器。
而任何yield之後的操作都可以放在exit函式中。
from contextlib import contextmanager
@contextmanager
def listtrans(alist):
thecopy=list(alist)
yield thecopy
alist[:]=thecopy
alist=
with listtrans(alist) as working:
print alist
yield返回的值相當於__enter__的返回值。
要注意的是,這不是異常安全的寫法,也就是說,當出現異常時,yield後的語句是不會執行的,想要異常安全,可用try捕捉異常:
from contextlib import contextmanager
@contextmanager
def listtrans(alist):
thecopy=list(alist)
try:
yield thecopy
except runtimeerror:
pass
alist[:]=thecopy
alist=
with listtrans(alist) as working:
raise runtimeerror
nested與closing
contextlib模組還有兩個好玩的方法:nested,closing。
nested:用來更方便的減少巢狀寫法:
當要巢狀的寫上下文管理器時:
with open('toreadfile', 'r') as reader:
with open('towritefile', 'w') as writer:
writer.writer(reader.read())
可以用nested簡化寫法:
with contextlib.nested(open('filetoread.txt', 'r'),
open('filetowrite.txt', 'w')) as (reader, writer):
writer.write(reader.read())
python2.7後nested就過時了:
with open('filetoread.txt', 'r') as reader,open('filetowrite.txt', 'w') as writer:
writer.write(reader.read())
closing(object):建立上下文管理器,在執行過程離開with語句時自動執行object.close():
class door(object) :
def open(self) :
print 'door is opened'
def close(self) :
print 'door is closed'
with contextlib.closing(door()) as door :
door.open()
python 上下文管理器
上下文管理器允許你在有需要的時候,精確地分配和釋放資源。使用上下文管理器最廣泛的案例就是with語句了。想象下你有兩個需要結對執行的相關操作,然後還要在它們中間放置一段 上下文管理器就是專門讓你做這種事情的。舉個例子 with open some file w as opened file open...
python上下文管理器
上下文管理器是乙個包裝任意 塊的物件。上下文管理器保證進入上下文管理器時,每次 執行的一致性 當退出上下文管理器時,相關資源會被正確 這裡被正確 指的是在 exit 方法自定義 比如關閉資料庫游標 值得注意的是,上下文管理器一定能夠保證退出步驟的執行。如果進入上下文管理器,根據定義,一定會有退出步驟...
Python 上下文管理器
python中的上下文管理器是乙個包裝任意 塊的物件。它在處理資源的開啟關閉 異常的處理等方面有很好的實現方法。1.上下文管理器的語法 假設我們需要讀取乙個檔案中的資料,如下 try test file open test.txt r contents test file.read finally ...