Python 上下文管理器

3 阅读3分钟

Python 上下文管理器(Context Manager)

上下文管理器是 Python 中管理资源的神器,核心作用是自动分配/释放资源,不用手动写繁琐的关闭、清理代码,避免资源泄漏。

最常见的场景:文件操作、数据库连接、网络请求、线程锁等。


一、核心概念

1. 它解决什么问题?

以前我们操作文件/连接,必须手动 close(),一旦忘记或出错,资源就会泄漏:

# 不推荐:容易忘记关闭,出错时还会跳过 close()
f = open("test.txt", "w")
f.write("hello")
# 若这里报错,文件永远不会关闭
f.close()  

上下文管理器会自动执行清理操作,无论代码正常运行还是报错。

2. 核心语法:with 语句

这是上下文管理器最常用、最简单的用法:

with 上下文管理器 as 变量:
    代码块

执行流程:

  1. 进入 with 时 → 执行初始化/资源申请
  2. 执行代码块
  3. 退出 with 时 → 自动执行资源释放/关闭(哪怕代码报错)

二、最常用的内置上下文管理器

1. 文件操作(最经典)

# 自动打开、自动关闭文件,无需写 close()
with open("test.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)

2. 线程锁

import threading
lock = threading.Lock()

with lock:  # 自动加锁、自动解锁
    # 安全操作共享数据
    pass

3. 临时文件、数据库连接等

Python 很多内置/第三方库都支持 with 语法。


三、自定义上下文管理器(两种方式)

方式1:类实现(最标准)

实现两个魔法方法:

  • __enter__():进入 with 时执行(申请资源)
  • __exit__():退出 with 时执行(释放资源)
class MyResource:
    # 初始化
    def __init__(self, name):
        self.name = name

    # 进入 with 时调用
    def __enter__(self):
        print(f"【开启】资源:{self.name}")
        return self  # 返回的值会被 as 接收

    # 退出 with 时调用(自动处理异常)
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"【关闭】资源:{self.name}")
        # exc_type:异常类型(无异常则为 None)
        return True  # 可选:True 表示忽略异常

# 使用
with MyResource("测试资源") as res:
    print(f"使用资源:{res.name}")

输出:

【开启】资源:测试资源
使用资源:测试资源
【关闭】资源:测试资源

方式2:装饰器实现(更简洁)

contextlib.contextmanager 装饰生成器函数,一行代码快速实现:

  • yield 之前 = __enter__
  • yield 之后 = __exit__
from contextlib import contextmanager

@contextmanager
def my_resource(name):
    # 进入 with:资源申请
    print(f"【开启】{name}")
    try:
        yield name  # 返回给 as 变量
    finally:
        # 退出 with:资源释放(无论是否报错都会执行)
        print(f"【关闭】{name}")

# 使用
with my_resource("简洁版资源") as res:
    print(f"使用:{res}")

效果和类版本完全一样,代码更短!


四、上下文管理器的优势

  1. 代码更简洁:不用写 try...finally 手动关闭
  2. 安全可靠无论代码正常/报错/中断,都会执行清理
  3. 可读性高:一眼看出资源的作用范围
  4. 通用强大:文件、数据库、网络、锁、临时目录都能用

五、实用小技巧:同时管理多个资源

# 同时打开两个文件,自动全部关闭
with open("a.txt") as f1, open("b.txt") as f2:
    data1 = f1.read()
    data2 = f2.read()

总结

  1. 上下文管理器 = with 语句,专门自动管理资源
  2. 核心:进入时申请,退出时释放
  3. 用法:
    • 直接用内置(open()、锁)
    • 自定义:类(__enter__/__exit__)或装饰器(@contextmanager
  4. 好处:安全、简洁、无资源泄漏