with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。
浅显得讲就是使用with语句,会自动帮我们在运行结束后进行清理,注意即使中途抛出异常,一样会进行清理,有点像unitest中 teardown的意思
举个最常见得例子:
####不使用with语句
f=open("my.log","r")
try:
lines=f.readlines()
except Exception as e:
raise e
finally:
f.close()
####使用with语句
with open("my.log","r") as f:
lines=f.readlines()
如果不适用with语句需要在我们不使用文件得时候手动去关闭文件,而with则不用,会自动帮我们处理,不管运行成功或者失败
通过例子我们可以大致看出来with语句得语法格式
with context_expression [as something]:
with-body
需要注意with语句操作得对象必须具有上下文管理器,也就是需要具有__ enter__方法,__ exit__方法
__enter __:入口方法,运行在with-body之前
__exit __:退出清理方法,运行在with-body之后
刚刚得例子虽然能说明问题,但是看得不够直观,我们来创建一个具有上下文管理器得对象
class my():
def __enter__(self):
print("i am enter")
def __exit__(self, exc_type, exc_val, exc_tb):
print("i am exit")
with my() as haha:
print("i am with body")
###输出
i am enter
i am with body
i am exit
上面得例子可以看出所有得运行过程,但是并没有体现出在with body中出错后会运行exit方法,来看下面得例子:
class my():
def __enter__(self):
print("i am enter")
def __exit__(self, exc_type, exc_val, exc_tb):
print("i am exit")
with my() as haha:
print("i am with body"+1)
###输出
i am enter
Traceback (most recent call last):
File "/Users/hjc/workspace/myutils/meiyouyong.py", line 8, in <module>
i am exit
print("i am with body"+1)
TypeError: must be str, not int
i am exit
可以看到exit方法被执行了,但是这里有个bug,如果我们给my类加个成员方法,这时haha找不到该方法
class my():
def __enter__(self):
print("i am enter")
def __exit__(self, exc_type, exc_val, exc_tb):
print("i am exit")
def run(self):
print("i am run")
with my() as haha:
haha.run()
###运行结果
i am enter
Traceback (most recent call last):
File "/Users/hjc/workspace/myutils/meiyouyong.py", line 10, in <module>
haha.run()
AttributeError: 'NoneType' object has no attribute 'run'
i am exit
上面得例子很明显haha并没有run方法,这是为什么呢,我们再看一下下面得例子
class my():
def __enter__(self):
print("i am enter")
def __exit__(self, exc_type, exc_val, exc_tb):
print("i am exit")
def run(self):
print("i am run")
with my() as haha:
my().run()
###运行结果
i am enter
i am run
i am exit
我们把haha改成了my()就可以了,为什么haha作为my()得替代没有呢,原因是my()先运行得是enter方法,而enter并没有返回值,导致haha替代my()时为None,自然没有run()方法
class my():
def __enter__(self):
print("i am enter")
def __exit__(self, exc_type, exc_val, exc_tb):
print("i am exit")
def run(self):
print("i am run")
with my() as haha:
print(haha)
###运行结果
i am enter
None
i am exit
找到问题得原因就简单了,我们只要运行enter时候把对象返回就好了
class my():
def __enter__(self):
print("i am enter")
return self #将对象返回
def __exit__(self, exc_type, exc_val, exc_tb):
print("i am exit")
def run(self):
print("i am run")
with my() as haha:
haha.run()
###运行结果
i am enter
i am run
i am exit
ok,到这里就结束了