3分钟让你掌握Python🐍中的上下文管理器(Context Managers),又是涨知识🧀的一天

142 阅读5分钟

又是学习进步的一天😊,今天我们来学习Python🐍中的上下文管理器,英文名字Context Managers

上下文管理器是一种用于管理资源的机制,它确保在使用资源后,无论使用过程中是否出现异常,都能够正确地释放或清理资源。Python中的上下文管理器主要通过 with 语句来实现,它可以提供更优雅、更安全的资源管理方式。

上下文管理器通常用于打开文件、数据库连接、网络连接、锁等需要手动管理的资源,以确保资源在使用完毕后能够正确地关闭或释放。

上下文管理器的基本结构

class MyContext:
    def __enter__(self):
        # 在进入上下文时执行的操作
        return resource  # 返回资源对象

    def __exit__(self, exc_type, exc_value, traceback):
        # 在退出上下文时执行的操作,无论是否发生异常
        # exc_type: 异常类型,exc_value: 异常值,traceback: 异常堆栈跟踪
        # 返回 True 表示异常被处理,不再传播;返回 False 或 None 表示异常继续传播

__enter____exit__ 是上下文管理器协议中的两个特殊方法,用于定义进入和退出上下文时的操作。当使用 with 语句管理资源时,这些方法会在进入和退出上下文时被自动调用,以确保资源的正确管理和释放。

__enter__ 方法

__enter__ 方法在进入上下文时被调用,它通常用于执行初始化操作或获取资源。该方法可以返回一个值,这个值会被绑定到 as 关键字之后的变量,从而可以在 with 块中使用。如果没有返回值,则默认返回上下文管理器自身。

class MyContext:
    def __enter__(self):
        print("你好我是 __enter__")
        return self  # 返回自身,以便在 with 语句中使用

    def __exit__(self, exc_type, exc_value, traceback):
        print("你好我是 __exit__")

    def hello(self):
        print('你好我是 小哥哥')
        
with MyContext() as context:
    context.hello()

输出结果为:

image.png

__exit__ 方法

__exit__ 方法在退出上下文时被调用,它通常用于执行清理操作或释放资源。它接受3个参数:exc_typeexc_valuetraceback。如果上下文是无异常地退出的,三个参数都将为 None。如果出现错误,按顺序返回异常类型、异常描述、异常对象。

__exit__ 方法中,您可以选择是否处理异常。如果您希望异常继续传播,只需在方法中不做任何处理即可。如果您希望处理异常并阻止其传播,可以在方法中返回 True。如果您希望异常继续传播,但也希望在处理完异常后执行一些清理操作,可以返回 FalseNone

class MyContext:
    def __enter__(self):
        print("你好我是 __enter__")

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            print("你好我是 __exit__,目前很正常")
        else:
            print(f"你好我是 __exit__,发生了异常: 异常类型是:{exc_type}, 异常的值为:{exc_value}")

with MyContext():
    print("大家好我是 context")
    raise ValueError("这里主动抛出个ValueError")

输出结果为: image.png

当异常时返回True就阻止了异常的传播,代码修改如下

def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            print("你好我是 __exit__,目前很正常")
        else:
            print(f"你好我是 __exit__,发生了异常: 异常类型是:{exc_type}, 异常的值为:{exc_value}")
            # 返回True阻止了异常的传播
            return True

image.png

这里举1个简单的例子🌰

示例:文件操作的上下文管理器

class FileContext:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        print('你好我是 __init__')

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        print('你好我是 __enter__')
        return self.file
        

    def __exit__(self, exc_type, exc_value, traceback):
        self.file.close()
        print('你好我是 __exit__')
        

with FileContext('example.txt', 'r') as file:
    contents = file.read()
    print(contents)
# 文件会在退出上下文时自动关闭

输出结果为:

image.png

上下文管理器其它方法介绍

除了上下文管理器的必需方法 __enter____exit__,我们可以选择性地定义以下可选方法来实现特定的行为或功能:

1.__init__ 方法:虽然不是上下文管理器协议的一部分,但在上下文管理器的实现中,您可以使用 __init__ 方法来执行一些初始化操作。

2.__iter__ 方法:如果您的上下文管理器表示一个可迭代对象,您可以定义 __iter__ 方法,使得上下文管理器本身成为可迭代的。迭代器教程可以参考3分钟带你了解Python中的生成器和迭代器

3.__len__ 方法:如果您的上下文管理器表示一个集合,您可以定义 __len__ 方法,用于返回集合中元素的数量。

4.__getitem____setitem__ 方法:如果您的上下文管理器表示一个可索引的对象,您可以定义这些方法以支持索引访问。

5.__call__ 方法:如果您希望您的上下文管理器可以像函数一样调用,您可以定义 __call__ 方法。

6.__str____repr__ 方法:用于返回对象的字符串表示和可打印的表达形式。

7.其他自定义方法:您可以根据需要定义其他自定义方法,以满足特定的行为和需求。比如我们在上方示例中的hello() 方法

需要注意的是,上下文管理器的核心功能是通过 __enter____exit__ 方法来实现的,其他方法主要是为了增强上下文管理器的功能或用法。在大多数情况下,只有 __enter____exit__ 方法是必需的,其他方法是可选的,可以根据需要进行定义。

总结

学会使用上下文管理器,具有提高代码的可读性、可维护性,并降低资源管理错误的风险。 今天的教程你学会了吗?