我发现以下行为至少怪异:
def errors():
try:
ErrorErrorError
finally:
return 10
print errors()
# prints: 10
# It should raise: NameError: name 'ErrorErrorError' is not defined
在return
子句中使用finally
时,异常消失。那是一个错误吗?有记录吗?
但真正的问题(以及我将标记为正确的答案)是:
什么是python开发人员允许这种奇怪行为的理由?
答案 0 :(得分:54)
在
return
子句中使用finally
时,异常消失。 ..有记录吗?
如果finally存在,则指定'cleanup'处理程序。执行try子句,包括任何except和else子句。如果任何子句中发生异常但未处理,则会临时保存该异常。 finally子句被执行。如果存在已保存的异常,则会在finally子句的末尾重新引发异常。 如果finally子句引发另一个异常或执行return或break语句,则保存的异常将丢失。
答案 1 :(得分:35)
您询问了Python开发人员的推理。我不能代表他们,但没有其他行为是有道理的。函数可以返回一个值,也可以引发异常;它不能两者兼顾。 “finally”子句的目的是提供“保证”运行的清理代码,无论例外情况如何。通过在finally子句中放置一个return语句,您已声明要返回一个值,无论如何,无论异常如何。如果Python表现得像你要求并引发异常,它将破坏“finally”子句的契约(因为它将无法返回你告诉它返回的值)。
答案 2 :(得分:4)
这是一个有趣的比较,在finally块中返回,在Java / C#/ Python / JavaScript中: http://www.gettingclever.com/2008/07/return-from-finally.html
编辑:链接坏了。从https://web.archive.org/web/20120426091446/http://www.gettingclever.com/2008/07/return-from-finally.html复制:
从最后返回
就在今天,我正在帮助解决Java中的一些错误 有趣的问题 - 如果你在try / catch中使用return会发生什么 声明?最后部分是否应该启动?我简化了 以下代码段的问题:
以下代码打印出来的是什么?
class ReturnFromFinally { public static int a() { try { return 1; } catch (Exception e) {} finally{ return 2; } } public static void main(String[] args) { System.out.println(a()); } }
我最初的猜测是,它应打印出
1
,我正在打电话return
,所以我假设一个人将被退回。但是,它不是 情况下:我理解逻辑,最后部分必须执行,但是 不知何故,我对此感到不安。让我们看看C#在这种情况下做了什么:
class ReturnFromFinally { public static int a() { try { return 1; } catch (System.Exception e) {} finally { return 2; } } public static void Main(string[] args) { System.Console.WriteLine(a()); } }
我更喜欢这种行为,控制流程不能搞砸 在最后一句中,所以它阻止我们在自己身上射击 脚丫子。只是为了完整起见,让我们检查一下其他什么 语言呢。
的Python:
def a(): try: return 1 finally: return 2 print a()
JavaScript的:
<script> function ReturnFromFinally() { try { return 1; } catch (e) { } finally { return 2; } } </script> <a onclick="alert(ReturnFromFinally());">Click here</a>
C ++和PHP中没有finally子句,所以我不能尝试最后一个 两种语言,我有编译器/解释器。
我们的小实验很好地表明,C#是最好的方法 对这个问题,但我很惊讶地了解到,所有的 其他语言以同样的方式处理问题。
答案 3 :(得分:3)
从最后回来是不一个好主意。我知道C#特别禁止这样做。