退出

  • 文章收藏

  • 消息

  • 修改资料

  • Python中的finally语句能在异常处理结束后进行一些清理工作,不论异常是否产生,是否被捕获,finally语句都会执行。但是对于finally语句的一些细节,各种教程和网上的描述都并不清楚。例如,如果在except和else子句中遇到return,后面的finally子句还会执行吗,如何执行?finally语句在什么情况下才不会执行呢?

    在except/else子句中return

    我写了下面这个函数作为试验:

    #Python 3.6.1
    >>> def func(x):
    ...     try:
    ...             float(x)
    ...     except (TypeError, ValueError) as e:
    ...             print(e.__class__.__name__+": "+str(e))
    ...             return "Return in except"
    ...     else:
    ...             print("No Error")
    ...             return "Return in else"
    ...     finally:
    ...             print("Finally is called")
    ...
    >>> func("3.5")
    No Error
    Finally is called
    'Return in else'
    >>> func("abc")
    ValueError: could not convert string to float: 'abc'
    Finally is called
    'Return in except'
    

    通过结果可以看到,只要try语句被执行,不论异常有没有发生,finally语句都会执行,即便函数在except/else子句中已经return,finally语句依然会执行,函数会在finally语句执行之后再return。

    在except/else子句中程序中断

    那么什么情况下finally语句不会执行呢?容易想到的就是程序完全中断。我们在except子句和else子句中分别raise KeyboardInterrupt和SystemExit, 通过下列例子进行测试:

    #Python 3.6.1
    >>> def func(x):
    ...     try:
    ...             float(x)
    ...     except (TypeError, ValueError) as e:
    ...             print(e.__class__.__name__+": "+str(e))
    ...             raise KeyboardInterrupt("KeyboardInterrupt in except")
    ...             return "Return in except"
    ...     else:
    ...             print("No Error")
    ...             raise SystemExit("SystemExit in else")
    ...             return "Return in else"
    ...     finally:
    ...             print("Finally is called")
    ...

    然后我们分别输入一个正确值和一个会引发异常的值:

    >>> func("3.5")
    No Error
    Finally is called
    SystemExit in else
    
    $username>

    可以看到,函数在SystemExit发生时退出了程序,并没有执行后面的return语句,但是finally语句依然在异常语句输出之前执行了。

    >>> func("aaa")
    ValueError: could not convert string to float: 'aaa'
    Finally is called
    Traceback (most recent call last):
      File "", line 3, in func
    ValueError: could not convert string to float: 'aaa'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "", line 1, in 
      File "", line 6, in func
    KeyboardInterrupt: KeyboardInterrupt in except
    >>>

    可以看到,函数在处理exception时,出现了另一个错误,并输出了Traceback,但是finally语句依然在异常语句输出之前执行了。

    在except/else子句中跳出循环

    那么循环的break语句是否可以跳过finally语句的执行呢?

    >>> while True:
    ...     try:
    ...             float("aaa")
    ...     except (TypeError, ValueError) as e:
    ...             print(e.__class__.__name__+": "+str(e))
    ...             break
    ...             print("After Break")
    ...     finally:
    ...             print("Finally is called")
    ...
    ValueError: could not convert string to float: 'aaa'
    Finally is called
    >>>

    可以看到,即便在except里面跳出了while循环,后面的finally语句依然被执行。而except子句中,break语句后面的语句则没有被执行。

    总结:

    只要try语句被执行,对应的finally语句就一定会被执行,即便通过SystemExit中断程序也不例外。

    • 如果在except/else子句中通过return跳出函数,则finally会在return语句之前执行。
    • 如果在except/else子句中通过break跳出循环,则finally在跳出循环后依然会执行。
    • 如果在except/else子句中通过SystemExit中断程序,或者产生了其它未捕获的异常,finally语句依然会执行,异常相关的描述会在finally语句执行完毕之后再输出到解释器中。

    总结成一句话,就是:只要try语句被执行,finally语句必定会在跳出try…except…else…结构之前执行,不论是语句顺序执行完毕,或者是因某种原因中途跳出。

    支付宝 微信 BTC
    支付宝扫一扫,向我打赏
    来源:原创

    声明:本站原创文章采用 BY-NC-SA 创作共用协议,转载时请以链接形式标明本文地址;非原创(转载)文章版权归原作者所有。 ©查看版权声明

  • 白銀の魔法師
  • 所有的信徒都别无二致,所有的信仰都一文不值
  • 发表评论

    你目前的身份是游客,请输入昵称和邮箱! 输入资料 关闭