python中的with上下文管理器

with 语句

with 语句是 Pyhton 提供的一种简化语法,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源。

在没有学习with的句法之前,通常我们都是使用try…finally语句,即使是在出现错误的情况下 也能运行某些清理代码。而今天学习的with语句就是对这些代码功能的一些简单封装。

with语句通常会使用在如下的几个环境之中:

  • 打开关闭一个文件
  • 释放一个锁
  • 创建一个临时的代码补丁
  • 在特殊环境下运行受保护的代码

那么,接下来我们就举打开关闭文件的例子说明:
我们先使用file()方法,看看两者之间有什么不同?

hosts=open('/etc/hosts')
try:
    for line in hosts:
        if line.startswith('#'):    #startswith以‘#’结尾
            continue
        print(line.strip())
finally:
    hosts.close()

上面的代码,我们是要打开位于/etc目录的hosts文件,使用file()方法之后,又手动调用close()关闭文件。
那么,使用with语句之后,我们可以重写为:

with open ('/etc/hosts') as hosts:
    for line in hosts:
        if line.startswith('#'):    #startswith以‘#’结尾
            continue
        print(line.strip())

with的执行过程:

  1. 在执行 with 语句时,首先执行 with 后面的 open 代码

  2. 执行完代码后,会将代码的结果通过 as 保存到 hosts 中

  3. 然后在下面实现真正要执行的操作

  4. 在操作后面,并不需要写文件的关闭操作,文件会在使用完后自动关闭

上下文管理器

任何实现了 _enter_(self) 和 _exit_(self,exc_type,exc_value,traceback) 方法的对象都可称之为上下文管理器,上下文管理器对象可以使用 with 关键字。显然,文件(file)对象也实现了上下文管理器协议。

从底层原理的角度来说,with语句的执行过程如下:

  1. 调用__enter__方法,任何返回值都会绑定到指定的as字句
  2. 执行内部代码块 调用__exit__方法
  3. 执行内部代码块 调用__exit__方法执行内部代码块 调用__exit__方法

我们可以模拟实现一个自己的文件类,让该类实现 _enter_() 和 _exit_() 方法。

class File():
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):
        print("entering")
        self.f = open(self.filename, self.mode)
        return self.f

    def __exit__(self, *args):
        print("will exit")
        self.f.close()

注:当我们打开文件时,就会自动调用_enter_,最终会返回该资源对象。当退出文件时,会自动调用__exit_方法,把文件关闭,做一些清理工作。

因为 File 类实现了上下文管理器,现在就可以使用 with 语句了。

with File('out.txt', 'w') as f:
    print("writing")
    f.write('哈哈哈,你好啊!')

contextlib模块

contextlib模块是实现上下文管理的另外一种方式,这个模块提供了与上下文管理器一起使用的辅助函数。它使用的是 contextmanager 装饰器,通过 yield 将函数分割成两部分,yield 之前的语句在\ enter 方法中执行,yield 之后的语句在 _exit_ 方法中执行。紧跟在 yield 后面的值是函数的返回值。

from contextlib import contextmanager

@contextmanager
def my_open(path, mode):
    f = open(path, mode)
    yield f
    f.close()

使用:

with my_open('out.txt', 'w') as f:
    f.write("hello , the simplest context manager")

参考文献:
【Python】with及上下文管理器的原理和应用
Pythong高级编程(第二版)

猜你喜欢

转载自blog.csdn.net/weixin_38819889/article/details/86552218