Python 的 with 关键字

493 阅读2分钟

With 关键字

With语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后关闭,线程中锁的获取和释放等。

要使用 with 语句,就需要一个上下文管理器。下面是与上下文管理器有关的概念。

  1. 上下文管理协议:包含方法 __ enter__() 和 __ exit__() ,支持该协议的对象要实现这两个方法。
  2. 上下文管理器:支持上下文管理协议的对象,定义执行with语句时要建立的运行时上下文,负责执行with语句块上下文中的进入与退出操作。 With 使用和原理
# 语法格式
with context_expression [as target(s)]
    with body
# 操作文件
with open(filename) as f:
    for line in f:
        print line

With 语句在执行时,会首先生成上下文管理器,先调用上下文管理器中的 __ enter__() 方法,然后执行 with 中的代码块,最后不管代码块中有没有发生异常,都会调用上下文管理器中的 __ exit__() 方法。类似 try - finally 的处理。

自定义上下文管理器

1、通常做法

自定义一个类,里面实现 enter() 和 exit() 方法(支持上下文管理协议)

class TimeNow:
    def __init__(self, lable):
        self.lable = lable
    def __enter__(self):
        self.start = time.time()
    def __exit__(self, exc_type, exc_val, exc_tb):
        end = time.time()
        logger.info("label: %s, cost time: %s", self.lable, end - self.start)

2、简单做法

使用 contextlib 中的装饰器 @contextmanager 装饰器,可以实现一个非常简洁的上下文管理器,并且它只需要是个方法就行。

@contextmanager
def time_now(lable):
    start = time.time()
    try:
        yield
    finally:
        end = time.time()
        logger.info("label: %s, cost time: %s", lable, end - start)

yield 之前的代码作为上下文管理器 __ enter__() 执行,可以在这里初始化一些信息,yield 之后的代码都会作为 __ exit__() 执行。