将“ with”语句转换为“ try”语句

时间:2019-11-18 18:15:36

标签: python with-statement magic-methods try-except

我想知道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**与。

2 个答案:

答案 0 :(得分:3)

根据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__,这将阻止调用代码返回True时看到该异常。
  3. finally块可确保__exit__恰好被调用一次。也就是说,如果没有引发异常,我们要调用它,但是如果第一个调用通过返回True或引发异常本身吞下了异常,则不要再次调用它。

答案 1 :(得分:1)

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

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

import sys

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