【问题标题】:Convert "with" statement to "try" statement将“with”语句转换为“try”语句
【发布时间】:2019-11-18 18:15:36
【问题描述】:

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

【问题讨论】:

  • PEP-343 提供您尝试编写的转换。
  • 谢谢,我会看的。

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


【解决方案1】:

根据引入上下文管理器的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 吞下异常或自身引发异常,则不会再次调用它。

【讨论】:

  • 谢谢。这是真正的答案。
【解决方案2】:

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

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

import sys

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

【讨论】:

  • 是的,真的是为了理解 with 语句,而不是用 try 代替 with 语句
  • 这不太一样;见 PEP-343。也就是说,__exit__ 方法如果返回 True,则可以抑制 do_something 引发的任何异常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多