python 提供了with语法用于简化资源操作的后续清除操作,实现原理建立在上下文管理器协议(实现__enter__和__exit__)之上。

上下文管理器:上下文管理器的本质就是能够支持with操作。任何实现了__enter__()和__exit__() 方法的对象都可以成为上下文管理器。

常见的文件对象就是实现了上下文管理器。

实现上下文管理器, 写一个自己的文件类

class MyFile(object):
    """支持上下文管理器的类"""
    def __init__(self, file_name, file_mode):
        """构造实例对象"""
        self.name = file_name
        self.mode = file_mode

    def __enter__(self):
        """上文 提供资源"""
        print("进入上文 获取资源")
        self.temp_file = open(self.name, self.mode)
        return self.temp_file

    def __exit__(self, exc_type, exc_val, exc_tb):
        """下文 提供资源关闭的方法"""
        print("进入下文 关闭资源")
        self.temp_file.close()

with MyFile("1.txt", "rb") as file:
    file_data = file.read(20)
    print("正在使用资源 数据为:%s" % file_data)

 __exit__(self, exe_type, exc_val, exc_tb)

exe_type代表异常类型,exc_value代表异常信息, exc_tb代表异常栈的跟踪信息(是一个异常对象 <traceback object at 0x0000021D44E91B48>)。

with执行体正常执行时,三者的值为None。

当with执行体出现异常时,三个参数会接受异常的信息,__exit__()方法会执行完,异常信息需要处理不然会抛出异常,所以要在with执行体内加入try-except进行捕获。

实现上下文管理器

Python 还提供了一个 contextmanager 的装饰器,更进一步简化了上下文管理器的实现方式。通过 yield 将函数分割成两部分,yield 之前的语句在 __enter__ 方法中执行,yield 之后的语句在 __exit__ 方法中执行。紧跟在 yield 后面的值是函数的返回值。

  •  from contextlib import contextmanager
  • @contextmanager
  • yield
from contextlib import contextmanager

@contextmanager
def myopen(name, mode):
    """提供上文 和 下文"""
    # 上文
    print("进入上文 获取资源")
    tfile = open(name, mode)

    yield tfile
    # 下文
    print("进入下文  关闭资源")
    tfile.close()

with myopen("1.txt", "rb") as file:
    file_data = file.read(20)
    print("正在使用资源 数据为:%s" % file_data)
10-06 21:00