关于python:return吃异常

return eats exception

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

1
2
3
4
5
6
7
8
9
def errors():
    try:
        ErrorErrorError
    finally:
        return 10

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

finally子句中使用return时,异常消失。 那是一个错误吗? 有记录吗?

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


The exception disappears when you use return inside a finally clause. .. Is that documented anywhere?

它是:

If finally is present, it specifies a ‘cleanup’ handler. The try clause is executed, including any except and else clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception, it is re-raised at the end of the finally clause. If the finally clause raises another exception or executes a return or break statement, the saved exception is lost.


您询问了Python开发人员的推理。 我不能代表他们,但没有其他行为是有道理的。 函数可以返回一个值,也可以引发异常; 它不能两者兼顾。"finally"子句的目的是提供"保证"运行的清理代码,无论例外情况如何。 通过在finally子句中放置一个return语句,您已声明要返回一个值,无论如何,无论异常如何。 如果Python表现得像你要求并引发了异常,它将破坏"finally"子句的契约(因为它将无法返回你告诉它返回的值)。


以下是在finally块中返回的有趣比较,其中包括 - Java / C#/ Python / JavaScript :(存档链接)

Return From Finally

Just today I was helping with some bug in Java and came across
interesting problem - what happens if you use return within try/catch
statement? Should the finally section fire up or not? I simplified the
problem to following code snippet:

What does the following code print out?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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());  
        }  
}

My initial guess would be, that it should print out 1, I'm calling
return, so I assume, one will be returned. However, it is not the
case:

the second return is executed

I understand the logic, finally section has to be executed, but
somehow I feel uneasy about this. Let's see what C# does in this case:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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());  
 }  
}

error CS0157 Control cannot leave the body of a finally clause

I prefer much rather this behavior, control flow cannot be messed with
in finally clause, so it prevents us from shooting ourself in the
foot. Just for the sake of completeness, let's check what other
languages do.

Python:

1
2
3
4
5
6
def a():  
 try:  
  return 1  
 finally:  
  return 2  
print a()

Python returns 2 as well

JavaScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function ReturnFromFinally()  
{  
 try  
 {  
  return 1;  
 }  
 catch (e)  
 {  
 }  
 finally  
 {  
  return 2;  
 }  
}  
 
Click here

JavaScript returns 2 as well

There is no finally clause in C++ and PHP, so I can't try out the last
two languages I have compiler/interpreter for.

Our little experiment nicely showed, that C# has the nicest approach
to this problem, but I was quite surprised to learn, that all the
other languages handle the problem the same way.


从最后回来并不是一个好主意。 我知道C#特别禁止这样做。