对于系统资源如文件、数据库连接、socket 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源。
如何正确的关闭一个文件呢?
1.普通版
def test0():
f = open("1.txt", "w")
f.write("0000")
f.close()
2.进阶版
def test1():
f = open("1.txt", "w")
try:
f.write("111111")
except Exception:
print("ERROR")
finally:
f.close()
3.高级版
def test2():
with open("1.txt", "w") as f:
f.write("2222")
使用with关键字的方法更为简洁,它的实现原理是什么,这就涉及到上下文管理器。
任何实现了 __enter__()
和__exit__()
方法的对象都可称之为上下文管理器
4.用类还原with的实现原理
class Test4(object):
def __init__(self, file_name, mode):
self.file_name = file_name
self.mode = mode
def __enter__(self):
self.f = open(self.file_name, self.mode)
return self.f
def __exit__(self,*args):
self.f.close()
with Test4("1.txt", "w") as f:
f.write("4444")
"""
首先Test4("1.txt", "w")初始化实例对象,
然后with会寻找类中是否有__enter__ 和 __exit__,
如果有则调用__enter__函数,
最后__enter__() 方法返回资源对象,这里就是你将要打开
的那个文件对象,__exit__() 方法处理一些清除工作。
"""
5.使用contextmanager装饰器,实现with功能
from contextlib import contextmanager
"""
Python 还提供了一个 contextmanager 的装饰器,更进一步简化
了上下文管理器的实现方式。通过 yield 将函数分割成两部分,yield 之前的
语句在 __enter__ 方法中执行,yield 之后的语句在 __exit__ 方法中执行。
紧跟在 yield 后面的值是函数的返回值。
"""
@contextmanager
def test5(path, mode):
f = open(path, mode)
yield f
f.close()
with test5('out.txt', 'w') as f:
f.write("5555")
总结:
Python 提供了 with 语法用于简化资源操作的后续清除操作,是 try/finally 的替代方法,实现原理建立在上下文管理器之上。此外,Python 还提供了一个 contextmanager 装饰器,更进一步简化上下管理器的实现方式。