標籤:
參考:http://blog.jobbole.com/64175/
上下文管理器的任務是:代碼塊執行前準備,代碼塊執行後收拾
1、如何使用上下文管理器:
如何開啟一個檔案,並寫入"hello world"
filename="my.txt"mode="w"writer=open(filename,mode)writer.write("hello world")writer.close()
當發生異常時(如磁碟寫滿),就沒有機會執行第5行。當然,我們可以採用try-finally語句塊進行封裝:
writer=open(filename,mode)try: writer.write("hello world")finally: writer.close()
當我們進行複雜的操作時,try-finally語句就會變得醜陋,採用with語句重寫:
with open(filename,mode) as writer: writer.write("hello world")
as指代了從open()函數返回的內容,並把它賦給了新值。with完成了try-finally的任務。
2、自訂上下文管理器
with語句的作用類似於try-finally,提供一種上下文機制。要應用with語句的類,其內部必須提供兩個內建函數__enter__和__exit__。前者在主體代碼執行前執行,後者在主體代碼執行後執行。as後面的變數,是在__enter__函數中返回的。
class echo(): def output(self): print "hello world" def __enter__(self): print "enter" return self #可以返回任何希望返回的東西 def __exit__(self,exception_type,value,trackback): print "exit" if exception_type==ValueError: return True else: return Flase >>>with echo as e: e.output() 輸出:enterhello worldexit
完備的__exit__函數如下:
def __exit__(self,exc_type,exc_value,exc_tb)
其中,exc_type:異常類型;exc_value:異常值;exc_tb:異常追蹤資訊
當__exit__返回True時,異常不傳播
3、contextlib模組
contextlib模組的作用是提供更易用的上下文管理器,它是通過Generator實現的。contextlib中的contextmanager作為裝飾器來提供一種針對函數層級的上下文管理機制,常用架構如下:
from contextlib import contextmanager@contextmanagerdef make_context(): print ‘enter‘ try: yield "ok" except RuntimeError,err: print ‘error‘,err finally: print ‘exit‘ >>>with make_context() as value: print value 輸出為: enter ok exit
其中,yield寫入try-finally中是為了保證異常安全(能處理異常)as後的變數的值是由yield返回。yield前面的語句可看作代碼塊執行前操作,yield之後的操作可以看作在__exit__函數中的操作。
以線程鎖為例:
@contextlib.contextmanagerdef loudLock(): print ‘Locking‘ lock.acquire() yield print ‘Releasing‘ lock.release() with loudLock(): print ‘Lock is locked: %s‘ % lock.locked() print ‘Doing something that needs locking‘ #Output:#Locking#Lock is locked: True#Doing something that needs locking#Releasing
4、contextlib.nested:減少嵌套
對於:
with open(filename,mode) as reader: with open(filename1,mode1) as writer: writer.write(reader.read())
可以通過contextlib.nested進行簡化:
with contextlib.nested(open(filename,mode),open(filename1,mode1)) as (reader,writer): writer.write(reader.read())
在python 2.7及以後,被一種新的文法取代:
with open(filename,mode) as reader,open(filename1,mode1) as writer: writer.write(reader.read())
5、contextlib.closing()
file類直接支援上下文管理器API,但有些表示開啟控制代碼的對象並不支援,如urllib.urlopen()返回的對象。還有些遺留類,使用close()方法而不支援上下文管理器API。為了確保關閉控制代碼,需要使用closing()為它建立一個上下文管理器(調用類的close方法)。
import contextlibclass myclass(): def __init__(self): print ‘__init__‘ def close(self): print ‘close()‘ with contextlib.closing(myclass()): print ‘ok‘ 輸出:__init__okclose()
python中的上下文管理器