将 "with" 语句转换为 "try" 语句

Convert "with" statement to "try" statement

我想知道 with 语句是如何工作的。我正在尝试转换以下内容:

with obj() as o:
    do_something()

进入这个:

o = obj.__enter__()
try:
    do_something()
except Exception as e:
    obj.__exit__(type(e),e, **I don't know what should be here**)
else:
    obj.__exit__(None, None , None)

那会怎么样呢?如果我在任何地方错了,请纠正我。我想知道用什么替换
**I don't know what should be here** 与.

如果只是作为一个学习实验,这很好。我认为实际上不应该使用它。您通常不需要直接调用 Python 的魔术方法。

您确实想在 finally 块中调用 __exit__。您要提供给 __exit__ 的三个参数可以通过调用 sys.exc_info.

获得
import sys

o = obj.__enter__()
try:
    do_something()
finally:
    obj.__exit__(*sys.exc_info())

根据引入上下文管理器的PEP-343,代码

with obj() as o:
    do_something()

等同于

mgr = obj()
exit = type(mgr).__exit__
value = type(mgr).__enter__(mgr)
exc = True

try:
    try:
        o = value
        do_something()
    except:
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
finally:
    if exc:
        exit(mgr, None, None, None)

一些注意事项:

  1. 我们不写o = type(mgr).__enter__(mgr)因为名字o只有在__enter__没有抛出异常时才被定义,允许我们在try处输入语句全部。 (还有其他方法可以处理这个问题,但这是我对 PEP-343 翻译的解释。)
  2. __exit__可以在两个不同的地方调用。如果我们捕获到一个异常,我们将有关该异常的信息传递给 __exit__,如果它 returns True.
  3. ,这可以防止调用代码看到它
  4. finally 块确保 __exit__ 只被调用一次。即,如果没有引发异常,我们想调用它,但如果第一次调用通过返回 True 吞下异常或引发异常本身,则不会再次调用它。