Python中with语句解析

python中一个使用使用with的场景是文件的打开和关闭:

with open('/file') as f:
	//do something

以上语句可以保证文件打开后能正确的关闭

那么with是怎么运行的呢?

带有一个“项目”的 with 语句的执行过程如下:

  1. 对上下文表达式(在 with_item 中给出的表达式)进行求值来获得上下文管理器。

  2. 载入上下文管理器的 enter() 以便后续使用。

  3. 载入上下文管理器的 exit() 以便后续使用。

  4. 唤起上下文管理器的 enter() 方法。

  5. 如果一个目标被包括在 with 语句中,则把它赋值为 enter() 的返回值。

备注 with 语句会保证如果 enter() 方法未发生错误地返回,则 exit() 将一定被调用。 因此,如果在对目标列表赋值期间发生错误,它将被当作在语句体内部发生的错误来处理。 参见下面的第 7 步。

  1. 执行语句体。

  2. 唤起上下文管理器的 exit() 方法。 如果语句体的退出是由异常导致的,则其类型、值和回溯信息将被作为参数传递给 exit()。 否则的话,将提供三个 None 参数。

    如果语句体的退出是由异常导致的,并且来自 exit() 方法的返回值为假,则该异常会被重新引发。 如果返回值为真,则该异常会被抑制,并会继续执行 with 语句之后的语句。

    如果语句体由于异常以外的任何原因退出,则来自 exit() 的返回值会被忽略,并会在该类退出正常的发生位置继续执行。

以下代码:

with EXPRESSION as TARGET:
    SUITE
在语义上等价于:

manager = (EXPRESSION)
enter = manager.__enter__
exit = manager.__exit__
value = enter()
hit_except = False

try:
    TARGET = value
    SUITE
except:
    hit_except = True
    if not exit(*sys.exc_info()):
        raise
finally:
    if not hit_except:
        exit(None, None, None)

除非有隐式的 特殊方法查找 被用于 enter() 和 exit()。

实现contextmanager的两种方式

  1. 实现 enter() 和 exit() 方法
class SuppressValueError:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        return exc_type is ValueError


with SuppressValueError():
    raise ValueError("发生错误")

print("程序继续执行")

exit()参数说明:

  • exc_type 异常类型,例如 ValueError
  • exc_val 异常对象
  • exc_tb 异常的 traceback 信息
    exit()返回值说明:
    想要抑制异常传播,返回True,否则返回False
  1. 使用 contextlib.contextmanager 装饰器
from contextlib import contextmanager


@contextmanager
def my_context():
    print("进入上下文")
    try:
        yield "hello"
    finally:
        print("退出上下文")

with my_context() as value:
    print(value)

这里最重要的是 yield:

  • yield 之前的代码:进入 with 时执行。
  • yield 返回的值:赋值给 as 后面的变量。
  • yield 之后的代码:退出 with 时执行。
  • finally:确保退出清理逻辑在正常退出和异常退出时都会执行。
    如果 with 内部发生异常,异常会重新进入生成器,因此可以在 yield 外部的 try...finally 中完成清理。
posted @ 2026-10-14 16:34  Hekk丶  阅读(2)  评论(0)    收藏  举报