← 返回首页

Python中with的使用

在 Python 中,with 语句用于简化资源管理,确保即使在代码执行过程中发生异常,也能自动释放资源(如文件、网络连接、锁等)。它的核心机制是 上下文管理协议(Context Manager Protocol)


✅ 一、基本语法

with 表达式 as 变量:
    # 使用变量的代码块
  • 表达式 必须返回一个 上下文管理器对象(实现了 __enter____exit__ 方法)
  • 变量__enter__ 方法的返回值
  • 无论代码块是否抛出异常,__exit__ 都会被调用

📁 二、经典示例:文件操作

❌ 不推荐(手动管理资源)

f = open('file.txt', 'r')
try:
    data = f.read()
finally:
    f.close()  # 必须显式关闭

✅ 推荐(使用 with

with open('file.txt', 'r') as f:
    data = f.read()
# 文件在此自动关闭,即使 read() 抛出异常!

💡 即使发生异常、returnbreak,文件也会被正确关闭。


🔧 三、自定义上下文管理器

方法 1:通过类实现

class MyResource:
    def __enter__(self):
        print("资源已获取")
        return self  # 返回给 as 后的变量
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("资源已释放")
        # 返回 True 可抑制异常(一般不建议)
        return False

# 使用
with MyResource() as res:
    print("正在使用资源")

输出:

资源已获取
正在使用资源
资源已释放

方法 2:使用 contextlib 装饰器(更简洁)

from contextlib import contextmanager

@contextmanager
def my_resource():
    print("获取资源")
    try:
        yield "资源对象"  # 相当于 __enter__ 的返回值
    finally:
        print("释放资源")

# 使用
with my_resource() as res:
    print(f"使用 {res}")

输出:

获取资源
使用 资源对象
释放资源

🧩 四、常见应用场景

场景 示例
文件操作 with open(...) as f:
线程锁 with threading.Lock():
数据库连接 with connection.cursor() as cur:
临时修改状态 with decimal.localcontext() as ctx:
测试 mock with mock.patch('module.func'):
改变工作目录 自定义上下文管理器

⚠️ 五、重要注意事项

  1. __exit__ 的参数

    def __exit__(self, exc_type, exc_val, exc_tb):
        # exc_type: 异常类型(如 ValueError)
        # exc_val: 异常实例
        # exc_tb: traceback 对象
    
    • 如果返回 True,会抑制异常(不抛出)
    • 通常应返回 False(让异常正常传播)
  2. 多个上下文管理器

    with open('in.txt') as fin, open('out.txt', 'w') as fout:
        fout.write(fin.read())
    

    或使用括号(Python 3.1+):

    with (
        open('in.txt') as fin,
        open('out.txt', 'w') as fout,
    ):
        ...
    
  3. as 不是必须的

    with lock:  # 只需执行 __enter__/__exit__,不需要返回值
        critical_section()
    

🆚 六、with vs try/finally

特性 with try/finally
代码简洁性 ✅ 高 ❌ 冗长
自动资源管理 ✅ 内置 ⚠️ 需手动写
可读性 ✅ 清晰表达“使用资源”意图 一般
灵活性 ⚠️ 依赖上下文管理器 ✅ 完全控制

最佳实践:只要支持上下文管理器,优先用 with


💡 总结

  • with 是 Python 的资源管理利器
  • 核心价值:自动清理,避免资源泄漏
  • 所有支持上下文管理的对象(文件、锁、数据库连接等)都应使用 with
  • 可通过类或 @contextmanager 轻松自定义

🐍 记住:“打开即关闭,使用即安全” —— 这就是 with 的哲学。