【问题标题】:Can I raise an exception in `__exit__`?我可以在 `__exit__` 中引发异常吗?
【发布时间】:2020-03-30 08:05:29
【问题描述】:

我可以在__exit__ 方法中引发异常吗?如果是这样,这个异常会传播到with 块之外吗?

例子:

class X:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        raise MyException()


with X() as x:
    pass

// What happens here? Is `MyException` propagated up the stack?

【问题讨论】:

  • 你试过了吗?
  • @user2357112supportsMonica 我这里目前没有python环境。即使我尝试过,我也不知道它是否只是偶然起作用,而是被定义为未定义的行为。我想知道我是否可以在所有情况和所有环境中安全地执行此操作。
  • 您可以在线试用。有很多在线 Python 环境可以在其中进行测试。例如,ideone.comrepl.it/languages/python3python.org/shell
  • “在执行此方法期间发生的异常将替换with 语句主体中发生的任何异常。” docs.python.org/3/library/stdtypes.html#contextmanager.__exit__
  • 我理解想知道某件事是否是已定义的行为(当人们认为一个似乎有效的测试意味着某件事可以做时,我经常感到沮丧)。另一方面,尝试它可以快速回答很多“我可以这样做”的问题,而答案是“不,如果你尝试会出现明显的错误”。这并不碰巧是其中一种情况,但这并不会降低尝试的效用。

标签: python with-statement


【解决方案1】:

此方法执行期间发生的异常将替换 with 语句主体中发生的任何异常。

https://docs.python.org/3/library/stdtypes.html#contextmanager.exit

我们可以看到with-statement 了解更多详情。无论 SUITE 是否抛出异常,__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)

【讨论】:

    猜你喜欢
    • 2014-07-29
    • 1970-01-01
    • 2015-12-30
    • 1970-01-01
    • 2012-10-31
    • 2018-11-26
    • 2017-07-24
    • 1970-01-01
    • 2010-10-07
    相关资源
    最近更新 更多