场景:今天因为需要测试一个服务,在测试前,需要把它依赖的服务干掉,在测试完成后(不论报错),再把服务起来。
因为它是其中的一个步骤,其他时间服务需开启,不适用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的方法,可以针对需要的场景做定制的上下文管理