3

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

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。虽然我已经能够在许多环境中复制,但我怀疑这与它有多大关系。

4

1 回答 1

11

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

@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"

正如文档所说:

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

另请注意,这BaseException不是Exception

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

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

于 2014-11-21T22:40:56.643 回答