with 语句用于使用上下文管理器定义的方法来包装块的执行。 这允许封装常见的 try…except…finally 使用模式以方便重用。
with_stmt ::= "with" ( "(" with_stmt_contents ","? ")" | with_stmt_contents ) ":" suite
with_stmt_contents ::= with_item ("," with_item)*
with_item ::= expression ["as" target]
带有一个“项目”的 with 语句的执行过程如下:
评估上下文表达式(with_item 中给出的表达式)以获得上下文管理器。
加载上下文管理器的 __enter__() 供以后使用。
加载上下文管理器的 __exit__() 供以后使用。
上下文管理器的 __enter__() 方法被调用。
如果目标包含在 with 语句中,则将 __enter__() 的返回值分配给它。
注意 with 语句保证如果 __enter__() 方法没有错误返回,那么 __exit__() 将始终被调用。 因此,如果在分配给目标列表期间发生错误,它将被视为与套件内发生的错误相同。 请参阅下面的步骤
上下文管理器的 __exit__() 方法被调用。 如果异常导致套件退出,其类型、值和回溯将作为参数传递给 __exit__()。 否则,提供三个 None 参数。
如果套件因异常而退出,并且 __exit__() 方法的返回值为 false,则会重新引发异常。 如果返回值为真,则异常被抑制,并继续执行 with 语句之后的语句。
如果套件因异常以外的任何原因退出,则忽略 __exit__() 的返回值,并在正常位置继续执行所采取的退出类型。
以下代码
with EXPRESSION as TARGET:
SUITE
在语义上等同于:
manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False
try:
TARGET = value
SUITE
except:
hit_except = True
if not exit(manager, *sys.exc_info()):
raise
finally:
if not hit_except:
exit(manager, None, None, None)