如何检查当前范围内是否有异常升级?

时间:2016-10-11 21:12:10

标签: python python-2.7 python-3.x debugging exception-handling

我使用以下代码调用具有适当数量参数的任意可调用f()

try:
    res = f(arg1)
except TypeError:
    res = f(arg1, arg2)

如果f()是一个双参数函数,只用一个参数调用它就会引发TypeError,因此可以在except分支中正确调用该函数。

问题是当f()是单参数函数且异常在f()的主体中升级时(可能是因为对某个函数的调用不好),例如:

def f(arg):
    map(arg) # raises TypeError

由于except的内部错误,控制流进入f()分支。当然,用两个参数调用f()会引发一个新的TypeError。然后我没有回溯到原始错误,而是使用两个参数追溯到f()的调用,这在调试时没那么有用。

我的代码如何识别不在当前范围内引发的异常来重新加注它们?

我想写这样的代码:

try:
    res = f(arg1)
except TypeError:
    if exceptionRaisedNotInTheTryBlockScope(): # <-- subject of the question
        raise
    res = f(arg1, arg2)

我知道我可以在exc_info = sys.exc_info()区块中添加except来使用walkarround。

其中一个假设是我无法控制f(),因为它是由我的模块的用户给出的。此外,__name__属性可能不是'f'。对f()的错误重复调用可能会引发内部异常。 walkarround不合适,因为它使f()的作者的调试变得复杂。

2 个答案:

答案 0 :(得分:0)

您可以捕获异常对象并进行检查。

try:
    res = f(arg1)
except TypeError as e:
    if "f() missing 1 required positional argument" in e.args[0]: 
        res = f(arg1, arg2)
    else:
        raise

坦率地说,不要花费额外的长度来对异常进行分类应该可以正常工作,因为如果错误源自f(),你应该同时获得原始回溯和辅助回溯 - 调试应该不是问题。 / p>

另外,如果你可以控制f(),你可以选择第二个参数,而不必再猜测它:

def f(a, b=None):
    pass

现在你可以用任何一种方式调用它。

这个怎么样:

import inspect

if len(inspect.getargspec(f).args) == 1:
    res = f(arg1)
else:
    res = f(arg1, arg2)

答案 1 :(得分:0)

终于明白了:

def exceptionRaisedNotInTheTryBlockScope():
    return sys.exc_info()[2].tb_next is not None

sys.exc_info()返回3个元素tuple。它的最后一个元素是最后一个异常的回溯。如果回溯对象是回溯链中的唯一对象,则异常在try块(https://docs.python.org/2/reference/datamodel.html)的范围内已经升级。

根据https://docs.python.org/2/library/sys.html#sys.exc_info,应该避免存储回溯值。