Skip to content
On this page

上下文管理器

1. 上下文管理器

一个类如果实现了__enter()____exit()___两个魔法方法,该类创建的对象我们称为上下文管理器。

对于上下文管理器我们可以使用with语句。进入with语句会调用上下文管理器的__enter__(),离开with语句作用域时会自动调用上下文管理器的__exit()__

py
class File(object):
    def __init__(self, file_name, open_mode):
        self.__file_name = file_name
        self.__open_mode = open_mode

    def __enter__(self):
        self.__file = open(self.__file_name, self.__open_mode)
        return self.__file

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.__file.close()


if __name__ == '__main__':
    # with语句使用上下文管理器
    with File("test.txt", "w") as file:
        # w模式不允许读取文件。操作出错,离开with语句时依然会执行__exit__()方法关闭文件
        content = file.read()  
        print(content)

with语句必须配合上下文管理器使用。上下文管理可以实现try...finally...的效果,它提供了一种简单且安全的方式来使用需要及时关闭和释放的资源。

with和上下文管理器的搭配非常类似于.Net中usingIDisposable的组合来使用和释放非托管资源,而using方式使用IDisposable对象本质就是使用了try...finally...结构,在finally语句中调用对象的CloseDispose方法。

2. contextmanager

上下文管理器除了上述使用方式之外,还提供了一个contextmanager装饰器配合yield生成器来简化上下文管理器的使用。

yield之前的内容在__enter()__中执行,yield之后的内容在__exit()__中执行。yield后面的值作为__enter()__返回值。

py
from contextlib import contextmanager


@contextmanager
def file(file_name, open_mode):
    _file = open(file_name, open_mode)  # yield前 在__enter__()中执行
    yield _file
    _file.close()  # yield后 在__exit__()中执行


if __name__ == '__main__':
    with file("test.txt", "w") as f:
        content = f.read()
        print(content)

Released under the MIT License.