sys.exc_info() 如何工作?

use*_*943 5 python exception python-2.7

sys.exc_info() 的行为在python 文档SOSO 中描述为:

  • 在一个 except 块或由一个 except 块调用的方法中,描述异常的三元组
  • 在其他地方,三重 None 值

那么为什么这个鼻子测试会失败呢?

def test_lang_stack(self):
    try:
        self.assertEquals((None,None,None), sys.exc_info()) # no exception
        a = 5 / 0
    except:
        self.assertNotEquals((None,None,None), sys.exc_info())  # got exception
    else:
        self.fail('should not get here')
    #finally:
    #    self.assertEquals((None,None,None), sys.exc_info()) # already handled, right?
    self.assertEquals((None,None,None), sys.exc_info())  # already handled, right?
Run Code Online (Sandbox Code Playgroud)

它在最后一行失败。如果你取消对 finally 块的注释,它会在那里失败。

我确实看到,如果我将所有这些放在一个方法中并从另一个方法调用,那么调用方法不会看到异常。exc_info 值似乎仍然设置为抛出异常的方法的末尾,即使在处理异常之后也是如此。

我在 OSX 上使用 python2.7。

Man*_*hit 5

在回答您的问题之前,我必须解释一下 sys.exc_info() 确定程序中最新/最近的异常:-

\n\n
\n

您的程序基本上是一系列函数调用,调用者\n函数调用被调用。因此,形成了一个调用堆栈/执行堆栈,其中为每个被调用的函数推送一个条目。此条目在 Python 中称为堆栈帧。因此,当在程序中调用 sys.exc_info() 时,它使用以下序列来确定最新的异常。它从当前堆栈帧开始,\n 这是您调用 sys.exc_info() 的函数。如果当前堆栈帧未处理/尚未处理异常,则从调用堆栈帧或其调用者获取信息,依此类推,直到找到正在处理/已处理的堆栈帧一个\n异常。这里,\xe2\x80\x9处理异常\xe2\x80\x9d被定义为\xe2\x80\x9c正在执行或\n已经执行了一个例外子句。\xe2\x80\x9d对于任何堆栈帧,只有\n有关的信息最近处理的异常是可以访问的。

\n
\n\n

现在,来看你的代码,

\n\n
def test_lang_stack(self):\n    try:\n        self.assertEquals((None,None,None), sys.exc_info()) # no exception\n        a = 5 / 0\n    except:\n        self.assertNotEquals((None,None,None), sys.exc_info())  # got exception\n    else:\n        self.fail('should not get here')\n    #finally:\n    #    self.assertEquals((None,None,None), sys.exc_info()) # already handled, right?\n    self.assertEquals((None,None,None), sys.exc_info())  # already handled, right?\n
Run Code Online (Sandbox Code Playgroud)\n\n

根据上面解释的过程,sys.exc_info() 将始终找到函数中正在处理的最近异常。因此,除非您显式调用,否则它永远不会是 None 元组sys.exec_clear()

\n\n

我希望,它可以帮助你。

\n


cfo*_*ish 2

在assertEquals() 和assertNotEquals() 中,您需要调用:

sys.exc_clear()
Run Code Online (Sandbox Code Playgroud)

这将为下一个错误清除一切。