等价于 try / except / finally 语句

Equivalence to a try / except / finally statement

来自 Python 简而言之

A try / except / finally statement, such as:

try:
    ...guarded clause...
except ...expression...:
    ...exception handler code...
finally:
    ...clean-up code...

is equivalent to the nested statement:

try:
    try:
        ...guarded clause...
    except ...expression...:
        ...exception handler code...
finally:
    ...clean-up code...
  1. 为什么相当于嵌套形式?
  2. 可以写成没有finally的形式吗?

    是否等同于

    try:
        ...guarded clause...
    except ...expression...:
        ...exception handler code...
        ...clean-up code...
    ...clean-up code...
    

谢谢。

不,您的替代代码并不完全等同于 try/except/finally 版本。要理解原因,请考虑如果在示例的 ...exception handler code... 部分内触发第二个异常会发生什么情况。

这是一个演示问题的演示:

try:
    print('in try')     # guarded code
    1/0                 # oops, a bug
except ZeroDivisionError:
    print('top of except')  # exception handling code
    name_does_not_exist     # oops, the exception handling code is buggy too
    print('end of except')  # this is a bad place for cleanup code
finally:
    print('in finally')   # this is a much better place to do cleanup

输出:

in try
top of except
in finally
Traceback (most recent call last):

  File "<ipython-input-17-63590fc64963>", line 6, in <module>
    name_does_not_exist     # oops, the exception handling code is buggy too

NameError: name 'name_does_not_exist' is not defined

请注意,end of except 消息永远不会打印出来,因为 NameError 出现在前一行。如果 line 是关键的清理代码,那么只有 tryexcept 的程序将无法 运行 它。但是,如果您将清理代码放在 finally 块中,则无论代码的任何其他部分是否引发任何异常,都可以保证 运行。

  1. 因为它就是这样定义的。因为以这种方式定义它是有用的和标准的,而且因为没有其他有用的方式来定义它。
  2. 是的,但不是你做的那样。

    try:
        do_stuff()
    except OneProblem:
        handle_it()
    except DifferentProblem:
        handle_that()
    finally:
        cleanup()
    

    相当于

    try:
        try:
            do_stuff()
        except OneProblem:
            handle_it()
        except DifferentProblem:
            handle_that()
    except:
        # Clean up if an unhandled exception happened, then restore the exception.
        cleanup()
        raise
    # Also clean up if we're not propagating an exception.
    cleanup()
    

就清理而言,总是会发生并且不会发生两次,尽管异常链接和回溯之类的行为可能会有所不同。

以下是我用来避免为 finally 代码创建函数并不得不从两个不同的地方调用它的方法。

try:
    pass
    pass
    1/0
    pass
    pass
    pass
    raise Exception('Success')
except Exception, e:
    if e.message != 'Success':
        import traceback
        print traceback.format_exc()

    print 'in finally'
    print 'in finally'
    print 'in finally'

    if e.message != 'Success':
        raise


Linux 上的输出:

Traceback (most recent call last):
  File "./test_finally.py", line 34, in <module>
    1/0
ZeroDivisionError: integer division or modulo by zero

in finally
in finally
in finally
Traceback (most recent call last):
  File "./test_finally.py", line 34, in <module>
    1/0
ZeroDivisionError: integer division or modulo by zero

shell returned 1