class FkResource: def __init__(self, tag): self.tag = tag print('構造器,初始化資源: %s' % tag) # 定義__enter__方法,with體之前的執行的方法 def __enter__(self): print('[__enter__ %s]: ' % self.tag) # 該返回值將作為as子句中變數的值 return 'fkit' # 可以返回任意型別的值 # 定義__exit__方法,with體之後的執行的方法 def __exit__(self, exc_type, exc_value, exc_traceback): print('[__exit__ %s]: ' % self.tag) # exc_traceback為None,代表沒有異常 if exc_traceback is None: print('沒有異常時關閉資源') else: print('遇到異常時關閉資源') return False # 可以省略,預設返回None也被看做是False with FkResource('孫悟空') as dr: print(dr) print('[with程式碼塊] 沒有異常') print('------------------------------') with FkResource('白骨精'): print('[with程式碼塊] 異常之前的程式碼') raise Exception print('[with程式碼塊] ~~~~~~~~異常之後的程式碼')執行上面的程式,可以看到如下輸出結果:
構造器,初始化資源: 孫悟空
[__enter__ 孫悟空]:
fkit
[with程式碼塊] 沒有異常
[__exit__ 孫悟空]:
沒有異常時關閉資源
------------------------------
構造器,初始化資源: 白骨精
[__enter__ 白骨精]:
[with程式碼塊] 異常之前的程式碼
[__exit__ 白骨精]:
遇到異常時關閉資源
Traceback (most recent call last):
File "C:UsersmengmaDesktop1.py", line 26, in <module>
raise Exception
Exception
注意,當出現異常時,如果 __exit__ 返回 False(預設不寫返回值時,即為 False),則會重新丟擲異常,讓 with as 之外的語句邏輯來處理異常;反之,如果返回 True,則忽略異常,不再對異常進行處理。
from contextlib import contextmanager @contextmanager def file_manager(name, mode): try: f = open(name, mode) yield f finally: f.close() with file_manager('a.txt', 'w') as f: f.write('hello world')這段程式碼中,函數 file_manager() 就是一個生成器,當我們執行 with as 語句時,便會開啟檔案,並返回檔案物件 f;當 with 語句執行完後,finally 中的關閉檔案操作便會執行。另外可以看到,使用基於生成器的上下文管理器時,不再用定義 __enter__() 和 __exit__() 方法,但需要加上裝飾器 @contextmanager,這一點新手很容易疏忽。