【问题标题】:Python Error Handling: finally vs. new line dedentedPython 错误处理:finally vs. new line dedented
【发布时间】:2013-10-03 01:15:25
【问题描述】:

当使用try 和except 进行错误处理时,是显式调用finally 还是只是转到从异常代码中删除的新行是否重要?例如,在什么情况下,下面的两个函数会产生不同的结果?

#Function 1 with finally
def final(x):
    try:
        print(x*x)

    except:
        print("Error")

    finally:
        print("End Function")


#Function 2 with new line dedent
def dedent(x):
    try:
        print(x*x)

    except:
        print("Error")

    print("End Function")

更新: 感谢finally 运行的解释,即使except 块中有错误。我想指出的另一件事是,即使您在 except 块中返回一个对象,finally 块也会运行。例如,即使在return 之后,下面的函数 3 也会打印,而函数 4 则不会。

#Function 3 with finally
def final(x):
    try:
        print(x*x)

    except:
        return 3

    finally:
        print("End Function 3")


#Function 4 with new line dedent
def dedent(x):
    try:
        print(x*x)

    except:
        return 3

    print("End Function 4")

test1 = final('test')
test2 = dedent('test')

【问题讨论】:

标签: python error-handling try-catch-finally


【解决方案1】:

如果到处都引发异常,区别就很明显了。

如果只有 try 块引发错误,那么它们是相同的。

#Function 1 with finally
def final(x):
    try:
        print(x*x)
        raise Exception
    except:
        print("Error")    
    finally:
        print("End Function")


#Function 2 with new line dedent
def dedent(x):
    try:
        print(x*x)
        raise Exception
    except:
        print("Error")    
    print("End Function")

final(10)
dedent(10)

但是。如果 except 块也引发错误,则 finally 块保证运行。

#Function 1 with finally
def final(x):
    try:
        print(x*x)
        raise Exception
    except:
        print("Error")
        raise Exception
    finally:
        print("This will be printed")

#Function 2 with new line dedent
def dedent(x):
    try:
        print(x*x)
        raise Exception
    except:
        print("Error")
        raise Exception
    print("This will not be printed")
final(10)
dedent(10)

【讨论】:

    【解决方案2】:

    即使except 处理程序引发新 异常,第一个版本仍将运行finally: 套件。在第二个版本中,最终的print() 将不会在这种情况下被执行:

    >>> def print(*args, **kw):
    ...     if not args or args[0] != 'End Function':
    ...         raise ValueError("Only print End Function!")
    ...     __builtins__.print(*args, **kw)
    ... 
    >>> final(0)
    End Function
    Traceback (most recent call last):
      File "<stdin>", line 3, in final
      File "<stdin>", line 3, in print
    ValueError: Only print End Function!
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 5, in final
      File "<stdin>", line 3, in print
    ValueError: Only print End Function!
    >>> dedent(0)
    Traceback (most recent call last):
      File "<stdin>", line 3, in dedent
      File "<stdin>", line 3, in print
    ValueError: Only print End Function!
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 5, in dedent
      File "<stdin>", line 3, in print
    ValueError: Only print End Function!
    

    请注意,final(0) 中打印的 first 内容是 End Function;没有为dedent(0) 打印此类文本。

    您永远不需要显式执行finally: 套件;它总是运行,即使您要使用return 提前退出函数,或者使用break 跳出循环或使用continue 跳过循环体的其余部分:

    >>> while True:
    ...     try:
    ...         print("In an infinite loop?")
    ...         break
    ...     finally:
    ...         print("Executed before the loop ends")
    ... 
    In an infinite loop
    Executed before the loop ends
    

    引用try statement documentation:

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

    和

    当return、break 或continue 语句在try...finally 语句的try 套件中执行时,finally 子句也会在途中执行'

    【讨论】:

      【解决方案3】:

      已经提到的except 块中有错误:

      def final(x):
          try:
              print(x*x)
      
          except:
              print("Error")
              damnit
      
          finally:
              print("End Function")
      
      def dedent(x):
          try:
              print(x*x)
      
          except:
              print("Error")
              damnit
      
          print("End Function")
      
      try:
          final("a")
      except Exception as e:
          print("There was an error:", e)
      #>>> Error
      #>>> End Function
      #>>> There was an error: global name 'damnit' is not defined
      
      try:
          dedent("a")
      except Exception as e:
          print("There was an error:", e)
      #>>> Error
      #>>> There was an error: global name 'damnit' is not defined
      

      还有return行为:

      def final(x):
          try:
              print(x*x)
      
          except:
              print("Error")
              return "Return inside"
      
          finally:
              print("End Function")
              return "Return outside"
      
      def dedent(x):
          try:
              print(x*x)
      
          except:
              print("Error")
              return "Return inside"
      
          print("End Function")
          return "Return outside"
      
      try:
          final("a")
      except Exception as e:
          print("There was an error:", e)
      #>>> Error
      #>>> End Function
      #>>> 'Return outside'
      
      try:
          dedent("a")
      except Exception as e:
          print("There was an error:", e)
      #>>> Error
      #>>> 'Return inside'
      

      【讨论】:

      • 感谢您指出return 的行为,我在玩我的代码时也注意到了这一点。
      【解决方案4】:

      根据PEP 341:

      try:
          block-1 ...
      except Exception1:
          handler-1 ...
      except Exception2:
          handler-2 ...
      else:
          else-block
      finally:
          final-block
      

      block-1 中的代码被执行。如果代码引发异常,则 测试各种 except 块:如果异常属于类 Exception1,handler-1被执行;否则,如果它是类的 Exception2、handler-2 被执行,以此类推。如果没有例外 引发,else块被执行。

      不管之前发生了什么,final-block都会执行一次 代码块已完成,任何引发的异常都已处理。即使 异常处理程序或 else 块中存在错误,并且新的 引发异常,final-block 中的代码仍在运行。

      所以正如Martjin所说,即使except引发另一个错误,finally中的代码也会被执行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-07-24
        • 1970-01-01
        • 2011-10-27
        • 2017-09-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多