【问题标题】:Python context manager not cleaning upPython上下文管理器没有清理
【发布时间】:2023-05-18 12:17:01
【问题描述】:

当我在上下文管理器中引发任何异常时,清理代码不会运行。例如:

from contextlib import contextmanager

try:
    raise BaseException()
except BaseException:
    print "bye from except"


@contextmanager
def say_goodbye():
    yield
    print "bye from context manager"

with say_goodbye():
    raise BaseException()

将输出:

bye from except
Traceback (most recent call last):
  File "", line 15, in 
BaseException

请注意,try/except 正确地捕获了异常,而 with 语句没有。 关于 with 语句应该如何工作,我有什么不明白的地方吗?

你可以在这里看到代码:http://pythonfiddle.com/context-manager-failing


仅供参考,我在 OSX mavericks 上运行 python 2.7。虽然我已经能够在许多环境中复制,但我怀疑这与它有多大关系。

【问题讨论】:

  • 这在contextmanager 文档中有完整的解释。最后一段完整地描述了它是如何工作的,告诉你如何使用try/except`或try/finally等。

标签: python python-2.7 exception-handling contextmanager try-except


【解决方案1】:

您需要自己添加异常处理:

@contextmanager
def say_goodbye():
    try:
        yield
    finally:
        print "bye from context manager"

以上内容确保finally 块始终运行,无论 with 块内是否有异常。如果您希望处理异常,则需要捕获这些异常并可能重新引发它们:

@contextmanager
def say_goodbye():
    try:
        yield
    except Exception as exc:
        print(exc)
    finally:
        print "bye from context manager"

正如the documentation 所说:

如果块中发生未处理的异常,它会在生成器中在发生 yield 的地方重新引发。因此,您可以使用 try...except...finally 语句来捕获错误(如果有),或确保进行一些清理。

还要注意BaseException 不是Exception

>>> isinstance(BaseException(), Exception)
False

您自己的异常应该继承自 Exception,而不是 BaseException

【讨论】:

    最近更新 更多