27

我发现以下行为至少很奇怪

def errors():
    try:
        ErrorErrorError
    finally:
        return 10

print errors()
# prints: 10
# It should raise: NameError: name 'ErrorErrorError' is not defined

当您returnfinally子句中使用时,异常会消失。那是一个错误吗?这在任何地方都有记录吗?

但真正的问题(以及我将标记为正确的答案)是:
python 开发人员允许这种奇怪行为的原因是什么?

4

4 回答 4

54

当您returnfinally子句中使用时,异常会消失。..这在任何地方都有记录吗?

这是:

如果 finally 存在,它指定一个“清理”处理程序。执行 try 子句,包括任何 except 和 else 子句。如果任一子句发生异常且未处理,则暂时保存该异常。finally 子句被执行。如果有一个保存的异常,它会在 finally 子句的末尾重新引发。如果 finally 子句引发另一个异常或执行 return 或 break 语句,则保存的异常将丢失。

于 2009-02-05T18:03:39.233 回答
36

您询问了 Python 开发人员的推理。我不能代表他们说话,但没有其他行为是有意义的。函数可以返回一个值,也可以引发异常;它不能两者兼得。“finally”子句的目的是提供“保证”运行的清理代码,而不考虑异常情况。通过在 finally 子句中放置一个 return 语句,你已经声明你想要返回一个值,不管发生什么,不管有什么异常。如果 Python 按照您的要求行事并引发异常,它将违反“finally”条款的合同(因为它无法返回您告诉它返回的值)。

于 2009-02-08T16:15:35.020 回答
4

这是一个关于 finally 块中返回的有趣比较,其中 - Java/C#/Python/JavaScript:(存档链接

从最后归来

就在今天,我正在帮助解决 Java 中的一些错误并遇到了一个有趣的问题——如果在 try/catch 语句中使用 return 会发生什么?finally 部分是否应该启动?我将问题简化为以下代码片段:

下面的代码打印出什么?

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());  
 }  
}  

错误 CS0157 控制不能离开 finally 子句的主体

我更喜欢这种行为,控制流不能在 finally 子句中被弄乱,所以它可以防止我们在脚下开枪。为了完整起见,让我们检查一下其他语言的功能。

Python:

def a():  
 try:  
  return 1  
 finally:  
  return 2  
print a()  

Python 也返回 2

JavaScript:

<script>  
function ReturnFromFinally()  
{  
 try  
 {  
  return 1;  
 }  
 catch (e)  
 {  
 }  
 finally  
 {  
  return 2;  
 }  
}  
</script>  
<a onclick="alert(ReturnFromFinally());">Click here</a>  

JavaScript 也返回 2

C++ 和 PHP 中没有 finally 子句,所以我不能尝试我有编译器/解释器的最后两种语言。

我们的小实验很好地表明,C# 对这个问题有最好的方法,但我很惊讶地发现,所有其他语言都以同样的方式处理这个问题。

于 2009-02-05T22:52:30.307 回答
2

从 finally 返回不是一个好主意。我知道 C# 明确禁止这样做。

于 2009-02-05T18:03:11.060 回答