前言:python
在对一些资源进行访问时,经常会出现操做不当或出现异常而致使资源没有获得必要关闭资源释放资源。例如:文件读取、socket等等。socket
下面内容以文件读取open方法为例。优化
原始操做:spa
1 f=open("filename") 2 f.write()#文件操做
3 f.close()
上述代码存在的问题:3d
(1)容易忘记文件关闭。code
(2)当文件操做出现异常致使程序提前离开,而没有执行关闭文件操做。对象
优化版:blog
1 try: 2 f=open("xxx") 3 f.write() #文件操做
4 except: 5 do something 6 finally: 7 f.close()
上述代码:资源
虽然解决由于出现异常而致使没有关闭文件的问题。可是这样使得代码冗余度加大,最最重要的是这样一点都不pythonic。it
with的用法:
with open("xxx") as f: f.write() #文件操做
问题来了,
with原理:
基本思想是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法。
紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块所有被执行完以后,将调用前面返回对象的__exit__()方法。
咱们具体来看看with为何能够作到自动关闭资源。
1 class Test(object): 2 def __enter__(self): 3 print("执行了 __enter__方法") 4 return "enter返回的内容" 5 6 def __exit__(self, type, value, trace): 7 print("执行了 __exit__方法") 8 9 10 with Test() as test: 11 print("test:", test)
运行结果:
执行了 __enter__方法 test: enter返回的内容 执行了 __exit__方法
执行过程分析:
推断:自动关闭文件是在__exit__()中调用文件关闭方法。
接下咱们改进一下代码来看看with为何能够处理异常出现的状况
1 class Test(object): 2 def __enter__(self): 3 print("执行了 __enter__方法") 4 return self 5 6 def __exit__(self, type, value, trace): 7 print("执行了 __exit__方法") 8 print("type:", type) 9 print("value:", value) 10 print("trace:", trace) 11 12 def do_something(self): 13 bar = 1 / 0 14 return bar + 10 15 16 17 with Test() as test: 18 test.do_something()
运行结果:
先给分析一下代码,Test()的__enter__()
方法返回新建立的Test对象,并赋值给变量test。而后执行会出现异常的方法,__exit__()中打印其三个参数。
根据运行结果,很明显__exit__()得三个参数分别是异常类、异常值、异常信息追踪。
实际上,当with中间代码体出现异常时__enter__()就会执行,并把异常相关信息赋值给三参数。同时在这个方法中咱们还能够加入清理资源,关闭文件等等操做。
总的看来,python的with语句是一个十分巧妙有效的机制,它可让代码更加的简洁、更加的pythonic。