Python的try finally块返回结果

120

下面是有趣的代码:

def func1():
    try:
        return 1
    finally:
        return 2

def func2():
    try:
        raise ValueError()
    except:
        return 1
    finally:
        return 3

func1()
func2()

请有人解释一下,这两个函数会返回什么结果以及为什么,即描述执行顺序


13
你其实不需要别人来解释结果会是什么,你可以直接尝试并观察。然而,如果你想要理性的解释,那就有些不同了。 - mgilson
如何运行Python代码:https://docs.python.org/3/tutorial/interpreter.html#interactive-mode - Hans Bouwmeester
有没有办法在这里获得使用 return 相同的效果?我尝试了 break 但 Python 说 break 不在循环内。 - Zack Light
4个回答

211
从Python 文档
无论是否发生异常,finally子句都会在离开try语句之前执行。当try子句中发生异常且未被except子句处理(或者发生在except或else子句中),在finally子句执行完毕后,异常将被重新引发。当通过break、continue或return语句离开try语句的任何其他子句时,finally子句也会被执行。一个更复杂的例子(在Python 2.5及以后版本中,可以在同一个try语句中使用except和finally子句):
因此,一旦使用return离开try/except块,它将设置返回值,并且finally块将始终执行,应该用于释放资源等。而使用另一个return将覆盖原始的返回值。
在您的特定情况下,func1()返回2,func2()返回3,因为这些是在finally块中返回的值。

1
Please include the source - thefourtheye
2
@thefourtheye 添加了文档文件的链接。 - lejlot
43
值得注意的是,根据这个例子,如果你在finally块中没有放置return语句,那么在try块中的任何 return 语句中的值实际上都会被返回(而不会被像None这样的值覆盖) 。 - scharfmn

56

它总是会进入finally块,因此会忽略tryexcept中的return。如果在tryexcept之前有一个return,它将返回该值。

def func1():
    try:
        return 1 # ignoring the return
    finally:
        return 2 # returns this return

def func2():
    try:
        raise ValueError()
    except:
        # is going to this exception block, but ignores the return because it needs to go to the finally
        return 1
    finally:
        return 3

def func3():
    return 0 # finds a return here, before the try except and finally block, so it will use this return 
    try:
        raise ValueError()
    except:
        return 1
    finally:
        return 3


func1() # returns 2
func2() # returns 3
func3() # returns 0

19
它实际上并不是“忽略”它,而是“覆盖”它,对吗?也就是说,如果有finally块且finally语句也有返回值,那么返回值就不会被忽略。另外,在try语句之前的返回语句会使得try语句无法到达,是吗? - zeusalmighty
1
我已经测试过了,你是完全正确的。 - 1408786user
你能解释一下,你是怎么测试它的吗? - Tomato Master

18

在之前放置print语句真的,真的很有帮助:

def func1():
    try:
        print 'try statement in func1. after this return 1'
        return 1
    finally:
        print 'after the try statement in func1, return 2'
        return 2

def func2():
    try:
        print 'raise a value error'
        raise ValueError()
    except:
        print 'an error has been raised! return 1!'
        return 1
    finally:
        print 'okay after all that let\'s return 3'
        return 3

print func1()
print func2()

这将返回:

try statement in func1. after this return 1
after the try statement in func1, return 2
2
raise a value error
an error has been raised! return 1!
okay after all that let's return 3
3
你会注意到,Python 总是返回最后一个被返回的东西,而不管代码中是否"达到"return 1。无论何时,finally块都会被运行,因此函数中最后要返回的东西就是在 finally 块中返回的内容。在 func1 中,这是2。在 func2 中,这是3。

你会注意到Python总是返回最后一个被返回的东西,无论在两个函数中代码是否“达到”了return 1。我想说的是,当Python在代码中找到finally块时,它会覆盖先前的返回值,而你上面的陈述并不是错误的,但我想说的是,在finally块执行后,控制权被转移,使最终的返回值在finally块中被覆盖。 - Ash Upadhyay

3

func1() 返回 2。 func2() 返回 3。

无论是否出现异常,finally 块都会被执行。

您可以使用调试器查看执行顺序。例如,请参见屏幕录像


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接