場景:今天因爲需要測試一個服務,在測試前,需要把它依賴的服務幹掉,在測試完成後(不論報錯),再把服務起來。
因爲它是其中的一個步驟,其他時間服務需開啓,不適用unittest通用的setup和teardown
所以想到寫一個類,通過上下文來管理服務狀態。
這是第一段測試代碼
# coding: utf-8
class C:
def __init__(self):
print("init")
def __enter__(self):
print("enter")
def __exit__(self, exc_type, exc_val, exc_tb):
print("exit")
def __del__(self):
print("del")
if __name__ == '__main__':
a = C()
print("st")
with a:
print("hi")
with a:
print("hi")
print("ed")
發現輸出是這樣的
init
st
enter
hi
exit
enter
hi
exit
ed
del
說明with一個已經存在的實例,會在起代碼塊開始和結束時執行實例的__enter__和__exit__,且可以執行多次。
而如果修改源碼,變成如下這樣
...
if __name__ == '__main__':
print("st")
with C():
print("hi")
with C():
print("hi")
print("ed")
發現輸出將是這樣的
st
init
enter
hi
exit
del
init
enter
hi
exit
del
ed
說明在with語句裏實例化類時,類的生命週期就只有with這一部分,所以會打印init和del兩次,而enter和exit仍然有效,該實例在with語句結束後該類就被刪除析構。
靈活的選擇with一個類/實例,合理安排init del和enter exit的方法,可以針對需要的場景做定製的上下文管理