人人都会AI编程

with 语句原理、执行流程

更新时间:2026-07-12

with 语句是 Python 中的上下文管理协议的语法糖,它的核心作用是:确保资源在使用完毕后能够被正确释放,无论过程中是否发生异常

你平时最常用的场景就是文件操作:

with open('data.txt', 'r') as f:
    content = f.read()
# 离开 with 块后,文件自动关闭,不需要调用 f.close()

其底层依赖的是一个约定好的协议:如果一个对象实现了 enterexit 两个魔术方法,那么它就是“上下文管理器”,可以直接用在 with 语句中。

  • enter:进入 with 块时被调用,负责获取资源并返回一个对象(通常就是自身),这个对象可以用 as 子句绑定到一个变量上。
  • exit:离开 with 块时被调用,负责释放资源。无论块内代码是正常结束还是抛出异常,exit 都会执行。它接收三个参数:异常类型、异常值、异常追溯,如果返回 True,则会吞掉异常,让程序继续执行;如果返回 FalseNone,异常会继续向上传播。

执行流程

我们用一个自定义的上下文管理器来拆解具体的执行过程:

class MyContext:
    def __enter__(self):
        print("1. 进入上下文,获取资源")
        return self                      # 返回的对象会赋给 as 后面的变量

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            print(f"3. 发生异常:{exc_type.__name__},但依然会释放资源")
        else:
            print("3. 正常结束,释放资源")
        return False                    # 不吞掉异常,继续向外抛出

with MyContext() as ctx:
    print("2. 执行业务逻辑")
    # raise ValueError("测试异常")      # 可取消注释测试异常场景

执行顺序如下:

  1. 计算表达式MyContext() 创建一个上下文管理器对象。
  2. 调用 enter:解释器自动调用该对象的 enter 方法,进入上下文。方法的返回值通过 as 绑定给变量 ctx
  3. 执行块内代码:顺序执行 with 代码块中的业务逻辑。
  4. 离开块时调用 exit
  • 如果没有异常,exc_typeexc_valexc_tb 均为 None,正常释放资源。
  • 如果块内代码抛出了异常,Python 会暂停块内执行,将异常信息传给 exit 的三个参数,然后执行释放资源的代码。之后根据返回值决定是否继续抛出异常。
  1. 清理完毕:无论何种情况,exit 都会被调用,资源一定被释放。

这种设计的好处是:将“资源获取”和“资源释放”强绑定在一起,开发者不必再担心忘记关闭文件、释放锁、断开数据库连接等问题。使用 with 比手动写 try ... finally 更简洁、更安全,也更符合 Python 的优雅哲学。