【问题标题】:return eats exception返回吃异常
【发布时间】:2010-10-05 17:56:54
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: python exception return finally


    【解决方案1】:

    当您在 finally 子句中使用 return 时,异常会消失。 .. 是否记录在任何地方?

    It is:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 合理行为:静态禁止 return 来自 finally。正如我们所见,这令人困惑。
      • 虽然我 100% 同意从 finally 返回是糟糕的代码,但它并没有歧义,总有一天有人可能会找到它的用例。永远不要说永远。
      【解决方案3】:

      这里有一个关于 finally 块中 return 的有趣比较 - Java/C#/Python/JavaScript: (archive link)

      最终归来

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

      下面的代码会打印什么?

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

      我更喜欢这种行为,控制流不能乱 在 finally 子句中,因此它可以防止我们在 脚。只是为了完整起见,让我们检查一下其他 语言可以。

      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# 有最好的方法 对于这个问题,但我很惊讶地得知,所有的 其他语言以同样的方式处理问题。

      【讨论】:

      • 这并不奇怪。所有语言都做唯一明智的事情(尊重 finally 子句),但 C# 除外,它可以防止自己在脚下开枪。这不符合 Python 的精神,它总是为你提供了所有你需要吊死自己的绳子 :-) “我们都是同意的成年人。”
      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-10-09
        • 2014-01-25
        • 2020-01-31
        • 1970-01-01
        • 2022-07-07
        • 2018-05-09
        • 2013-12-05
        • 1970-01-01
        相关资源
        最近更新 更多