• 8.4. try 语句

    8.4. try 语句

    try 语句可为一组语句指定异常处理器和/或清理代码:

    1. try_stmt ::= try1_stmt | try2_stmt
    2. try1_stmt ::= "try" ":" suite
    3. ("except" [expression ["as" identifier]] ":" suite)+
    4. ["else" ":" suite]
    5. ["finally" ":" suite]
    6. try2_stmt ::= "try" ":" suite
    7. "finally" ":" suite

    except 子句指定一个或多个异常处理器。 当 try 子句中没有发生异常时,没有异常处理器会被执行。 当 try 子句中发生异常时,将启动对异常处理器的搜索。 此搜索会依次检查 except 子句,直至找到与该异常相匹配的子句。 如果存在无表达式的 except 子句,它必须是最后一个;它将匹配任何异常。 对于带有表达式的 except 子句,该表达式会被求值,如果结果对象与发生的异常“兼容”则该子句将匹配该异常。 一个对象如果是异常对象所属的类或基类,或者是包含有兼容该异常的项的元组则两者就是兼容的。

    如果没有 except 子句与异常相匹配,则会在周边代码和发起调用栈上继续搜索异常处理器。 1

    如果在对 except 子句头中的表达式求值时引发了异常,则原来对处理器的搜索会被取消,并在周边代码和调用栈上启动对新异常的搜索(它会被视作是整个 try 语句所引发的异常)。

    当找到一个匹配的 except 子句时,该异常将被赋值给该 except 子句在 as 关键字之后指定的目标,如果存在此关键字的话,并且该 except 子句体将被执行。 所有 except 子句都必须有可执行的子句体。 当到达子句体的末尾时,通常会转向整个 try 语句之后继续执行。 (这意味着如果对于同一异常存在有嵌套的两个处理器,而异常发生于内层处理器的 try 子句中,则外层处理器将不会处理该异常。)

    当使用 as 将目标赋值为一个异常时,它将在 except 子句结束时被清除。 这就相当于

    1. except E as N:
    2. foo

    被转写为

    1. except E as N:
    2. try:
    3. foo
    4. finally:
    5. del N

    这意味着异常必须赋值给一个不同的名称才能在 except 子句之后引用它。 异常会被清除是因为在附加了回溯信息的情况下,它们会形成堆栈帧的循环引用,使得所有局部变量保持存活直到发生下一次垃圾回收。

    在一个 except 子句体被执行之前,有关异常的详细信息存放在 sys 模块中,可通过 sys.exc_info() 来访问。 sys.exc_info() 返回一个 3 元组,由异常类、异常实例和回溯对象组成(参见 标准类型层级结构 一节),用于在程序中标识异常发生点。 当从处理异常的函数返回时 sys.exc_info() 的值会恢复为(调用前的)原值。

    如果控制流离开 try 子句体时没有引发异常,并且没有执行 return, continuebreak 语句,可选的 else 子句将被执行。 else 语句中的异常不会由之前的 except 子句处理。

    如果存在 finally,它将指定‘清理’处理器。 try 子句会被执行,包括任何 exceptelse 子句。 如果在这些子句中发生任何未处理的异常,该异常会被临时保存。 finally 子句将被执行。 如果存在被保存的异常,它会在 finally 子句的末尾被重新引发。 如果 finally 子句引发了另一个异常,被保存的异常会被设为新异常的上下文。 如果 finally 子句执行了 returnbreak 语句,被保存的异常会被丢弃:

    1. >>> def f():
    2. ... try:
    3. ... 1/0
    4. ... finally:
    5. ... return 42
    6. ...
    7. >>> f()
    8. 42

    finally 子句执行期间,程序不能获取异常信息。

    return, breakcontinue 语句在一个 tryfinally 语句的 try 子句体中被执行时,finally 子句也会‘在离开时’被执行。 continue 语句在 finally 子句中是不合法的。 (原因在于当前实现存在一个问题 —- 此限制可能会在未来去除)。

    函数的返回值是由最后被执行的 return 语句所决定的。 由于 finally 子句总是被执行,因此在 finally 子句中被执行的 return 语句总是最后被执行的:

    1. >>> def foo():
    2. ... try:
    3. ... return 'try'
    4. ... finally:
    5. ... return 'finally'
    6. ...
    7. >>> foo()
    8. 'finally'

    有关异常的更多信息可以在 异常 一节找到,有关使用 raise 语句生成异常的信息可以在 raise 语句 一节找到。