finally块中的break语句吞下异常

时间:2016-02-19 12:41:39

标签: python

考虑:

def raiseMe( text="Test error" ):
    raise Exception( text )

def break_in_finally_test():
    for i in range(5):
        if i==2:
            try:
                raiseMe()
            except:
                raise
            else:
                print "succeeded!"
            finally:
                print "testing this!"
                break

if __name__=='__main__':
    break_in_finally_test()

我希望看到Exception( "Test error" )被提升,而只是#34;测试这个"打印出来。当然,目的是只召唤raiseMe()一次,无论我们成功与否 - 但如果它引起异常,我本来想看到它!

为什么break会吞下我明确提出的异常?

4 个答案:

答案 0 :(得分:32)

来自https://docs.python.org/2.7/reference/compound_stmts.html#finally

  

如果finally存在,则指定'cleanup'处理程序。执行try子句,包括任何except和else子句。如果任何条款中发生异常且未处理,则暂时保存该异常。
执行finally子句。如果存在已保存的异常,则在finally子句的末尾重新引发。 如果finally子句引发另一个异常或执行return或break语句,则丢弃已保存的
异常

这也反映了PEP341之前try...finally声明所期望的行为:

这是除了finally块之外的尝试看起来像PEP341之前的那样:

try:
    try:
        raiseMe()
    except:
        raise
finally:
    #here is where cleanup is supposed to happen before raising error
    break
    #after finally code: raise error

由于错误的引发从未在finally块中发生,因此它实际上从未被提升过。

为了保持与Python< = 2.4的向后兼容性,必须以这种方式完成。

答案 1 :(得分:5)

来自文档Error Handling Docs

  

在离开try语句之前总是执行finally子句,无论是否发生了异常。

你的异常永远不会被提出,因为你在try语句被完全评估之前就中断了。

答案 2 :(得分:1)

认为经过反思,这是因为break实际上将StopIteration提升为for-loop的“break”。这实际上不是很直观,也没有特别详细记录(例如,1没有提及)。也许有人可以更好地确认/解释它?

答案 3 :(得分:0)

具有以下代码结构:

def func():
    try: 
        driver.do("something")
    except TimeoutException:
        pass
    finally:
        result = driver.do("something else")
        return result

通过pylint得到异常:

return statement in finally block may swallow exception (lost-exception)

解决方案是将 return 放在 finally 语句之外:

def func():
    try: 
        driver.do("something")
    except TimeoutException:
        pass
    finally:
        result = driver.do("something else")
    return result # <<