python中的with語句使用於對資源進行訪問的場合,保證不管處理過程中是否發生錯誤或者異常都會執行規定的__exit__(“清理”)操作,釋放被訪問的資源,比如有文件讀寫后自動關閉、線程中鎖的自動獲取和釋放等。
與python中with語句有關的概念有:上下文管理協議、上下文管理器、運行時上下文、上下文表達式、處理資源的代碼段。
with語句的語法格式如下:
with context_expression [as target(s)]:
with-body
with語句的執行原理:
context_manager=context_expression exit=type(context_manager).__exit__ value=type(context_manager).__enter__(context_manager) exc=True try: try: targer=value with-body except: exc=False if not exit(context_manager, *sys.exc_info()): raise finally: if exc: exit(context_manager,None,None,None)
從with的執行原理中可以看出,context_expression返回的對象中必須具有__exit__和__enter__兩個方法,而且先檢查__exit__方法在檢查__enter__方法。無論在執行with-body中的函數體的過程中是否會發生異常,都會執行__exit__函數,如果沒有異常,退出函數的中參數都為None;如果發生異常,則使用sys.exc_info()返回的異常信息為參數退出,並且當__exit__方法返回True時,忽略異常,當__exit__方法返回False時,拋出異常,此時,__exit__函數中就不需要再拋出異常,只需要將__exit__函數的返回值設為False就可以了。
例子:
自定義支持上下文管理協議的類:
不拋出異常的函數體:
拋出異常的函數體:
python提供了contextlib模塊,省去了寫__enter__和__exit__重復工作了。contextlib模塊提供了3個對象:contextmanager裝飾器、上下文管理器closing和nested函數。
裝飾器contextmanager用來對生成器函數進行裝飾,生成器函數被裝飾以后,返回的是一個上下文管理器。
yield語句之前的代碼在__enter__函數中執行,yield語句之后的代碼在__exit__函數中執行。
closing上下文管理器包裝起來的對象必須提供close()方法。
closing的執行原理如下:
class closing(object): def __init__(self,thing): self.thing = thing def __enter__(self): return self.thing def __exit__(self, *exc_info): self.thing.close()
因此,closing上下文管理器包裝的對象必須提供close()函數。
nested函數可以將多個上下文管理器組織在一起,避免使用嵌套的with語句。
with nested(A(),B(),C()) as (X,Y,Z):
with-body
類似於:
with A() as X:
with B() as Y:
with C() as Z:
with-body