Python中with语句解析
python中一个使用使用with的场景是文件的打开和关闭:
with open('/file') as f:
//do something
以上语句可以保证文件打开后能正确的关闭
那么with是怎么运行的呢?
带有一个“项目”的 with 语句的执行过程如下:
-
对上下文表达式(在 with_item 中给出的表达式)进行求值来获得上下文管理器。
-
载入上下文管理器的 enter() 以便后续使用。
-
载入上下文管理器的 exit() 以便后续使用。
-
唤起上下文管理器的 enter() 方法。
-
如果一个目标被包括在 with 语句中,则把它赋值为 enter() 的返回值。
备注 with 语句会保证如果 enter() 方法未发生错误地返回,则 exit() 将一定被调用。 因此,如果在对目标列表赋值期间发生错误,它将被当作在语句体内部发生的错误来处理。 参见下面的第 7 步。
-
执行语句体。
-
唤起上下文管理器的 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的两种方式
- 实现 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
- 使用 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 中完成清理。

浙公网安备 33010602011771号