一 、with
語句的原理
- 上下文管理協議(Context Management Protocol):包含方法
__enter__()
和__exit__()
,支持該協議的對象要實現這兩個方法。 - 上下文管理器(Context Manager):支持上下文管理協議的對象,這種對象實現了
__enter__()
和__exit__()
方法。上下文管理器定義執行with
語句時要建立的運行時上下文,負責執行with
語句塊上下文中的進入與退出操作。通常使用with
語句調用上下文管理器,也可以通過直接調用其方法來使用。
說完上面兩個概念,我們再從with
語句的常用表達式入手,一段基本的with
表達式,其結構是這樣的:
1 with EXPR as VAR: 2 3 BLOCK
其中EXPR可以是任意表達式;as VAR是可選的。其一般的執行過程是這樣的:
- 執行EXPR,生成上下文管理器context_manager;
- 獲取上下文管理器的
__exit()__
方法,並保存起來用於之后的調用; - 調用上下文管理器的
__enter__()
方法;如果使用了as
子句,則將__enter__()
方法的返回值賦值給as
子句中的VAR; - 執行BLOCK中的表達式;
- 不管是否執行過程中是否發生了異常,執行上下文管理器的
__exit__()
方法,__exit__()
方法負責執行“清理”工作,如釋放資源等。如果執行過程中沒有出現異常,或者語句體中執行了語句break/continue/return
,則以None
作為參數調用__exit__(None, None, None)
;如果執行過程中出現異常,則使用sys.exc_info
得到的異常信息為參數調用__exit__(exc_type, exc_value, exc_traceback)
; - 出現異常時,如果
__exit__(type, value, traceback)
返回False,則會重新拋出異常,讓with
之外的語句邏輯來處理異常,這也是通用做法;如果返回True,則忽略異常,不再對異常進行處理。
二、自定義上下文管理器
Python
的with
語句是提供一個有效的機制,讓代碼更簡練,同時在異常產生時,清理工作更簡單。
# coding = utf-8 # 2019/7/19 Luckyxxt:有趣的事,Python永遠不會缺席! #!/usr/bin/env python class DBManager(object): def __init__(self): pass def __enter__(self): print('__enter__') return self def __exit__(self, exc_type, exc_val, exc_tb): print('__exit__') return True def getInstance(): return DBManager() with getInstance() as dbManagerIns: print('with demo')
with后面必須跟一個上下文管理器,如果使用了as,則是把上下文管理器的 __enter__() 方法的返回值賦值給 target,target 可以是單個變量,或者由“()”括起來的元組(不能是僅僅由“,”分隔的變量列表,必須加“()”)
代碼運行結果如下:
1 ''' 2 __enter__ 3 with demo 4 __exit__ 5 6 '''
結果分析:當我們使用with的時候,__enter__方法被調用,並且將返回值賦值給as后面的變量,並且在退出with的時候自動執行__exit__方法
1 class With_work(object): 2 def __enter__(self): 3 """進入with語句的時候被調用""" 4 print('enter called') 5 return "xxt" 6 7 def __exit__(self, exc_type, exc_val, exc_tb): 8 """離開with的時候被with調用""" 9 print('exit called') 10 11 12 with With_work() as f: 13 print(f) 14 print('hello with')
1 ''' 2 enter called 3 xxt 4 hello with 5 exit called 6 7 '''
三、總結
自定義上下文管理器來對軟件系統中的資源進行管理,比如數據庫連接、共享資源的訪問控制等。
轉自:https://www.cnblogs.com/xxtalhr/p/11211347.html#_labelTop