上下文管理器可以用来包装任意格式的代码块,被用得最多地方就是,作为确保资源被正确清理的一种方式。
with open('/path/to/file', 'r') as f:
f.read()
本质上讲,with语句是对其后面的代码进行求值,open表达式会返回一个对象,该对象包含两个方法,__enter__和__exit__。
class Database(object):
...
def __enter__(self):
self.connect()
return self
def __exit__(self, exc_type, exc_instance, traceback):
self.close()
__enter__方法只接受self参数,而__exit__方法还接受异常类型,异常实例和回溯选择(如果没有发生异常,则三个位置参数都是None)。
需要注意的是,只有__enter__的返回值会赋值给as后面的变量。
还有,__exit__方法只是向流程链上传播一场,这是通过返回False实现的,根本不需要与实例进行交互。
我们可以编写自己的上下文管理器。__enter__方法负责执行一些配置,__exit__方法则一般负责异常处理,资源清理等情况。
一般把上下文管理器视为try-except的替代品,而上下文管理器有价值的应用之一是必须在except子句中完成的工作很重要,且在应用程序中多处复用的情况。
- contextlib
可以用contextlib库简化构建上下文管理器的代码,例如:
from contextlib import contextmanager
@contextmanager
def tag(name):
print("<%s>" % name)
yield
print("</%s>" % name)
with tag("h1"):
print("hello")
print("world")
tag里yield之前的就在with代码块之前发生,之后的同理。