|
| 1 | +# 3.4 异常 |
| 2 | + |
| 3 | +> 来源:[3.4 Exceptions](http://www-inst.eecs.berkeley.edu/~cs61a/sp12/book/interpretation.html#exceptions) |
| 4 | +
|
| 5 | +> 译者:[飞龙](https://github.com/wizardforcel) |
| 6 | +
|
| 7 | +> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) |
| 8 | +
|
| 9 | +程序员必须总是留意程序中可能出现的错误。例子数不胜数:一个函数可能不会收到它预期的信息,必需的资源可能会丢失,或者网络上的连接可能丢失。在设计系统时,程序员必须预料到可能产生的异常情况并且采取适当地措施来处理它们。 |
| 10 | + |
| 11 | +处理程序中的错误没有单一的正确方式。为提供一些持久性服务而设计的程序,例如 Web 服务器 应该对错误健壮,将它们记录到日志中为之后考虑,而且在尽可能长的时间内继续接受新的请求。另一方面,Python 解释器通过立即终止以及打印错误信息来处理错误,便于程序员在错误发生时处理它。在任何情况下,程序员必须决定程序如何对异常条件做出反应。 |
| 12 | + |
| 13 | +异常是这一节的话题,它为程序的错误处理提供了通用的机制。产生异常是终止程序正常执行流的技巧,发射异常情况产生了的信号,并直接返回到用于响应异常情况的程序的封闭部分。Python 解释器每次在检测到语句或表达式错误时抛出异常。用户也可以使用`raise`或`assert`语句来抛出异常。 |
| 14 | + |
| 15 | +**抛出异常。**异常是一个对象实例,它的类直接或间接继承自`BaseException`类。第一章引入的`assert`语句产生`AssertionError`类的异常。通常,异常实例可以使用`raise`语句来抛出。`raise`语句的通用形式在 [Python 文档](http://docs.python.org/py3k/reference/simple_stmts.html#raise)中描述。`raise`的最常见的作用是构造异常实例并抛出它。 |
| 16 | + |
| 17 | +```py |
| 18 | +>>> raise Exception('An error occurred') |
| 19 | +Traceback (most recent call last): |
| 20 | + File "<stdin>", line 1, in <module> |
| 21 | +Exception: an error occurred |
| 22 | +``` |
| 23 | + |
| 24 | +当异常产生时,当前代码块的语句不会继续执行。除非异常被解决了(下面会描述),解释器会直接返回到“读取-求值-打印”交互式循环中,或者在 Python 以文件参数启动的情况下会完全终止。此外,解释器会打印栈回溯,它是结构化的文本块,描述了执行分支中的一系列嵌套的活动函数,它们是异常产生的位置。在上面的例子中,文件名称`<stdin>`表示异常由用户在交互式会话中产生,而不是文件中的代码。 |
| 25 | + |
| 26 | +**处理异常。**异常可以使用封闭的`try`语句来处理。`try`语句有多个子句组成,第一个子句以`try`开始,剩下的以`except`开始。 |
| 27 | + |
| 28 | +```py |
| 29 | +try: |
| 30 | + <try suite> |
| 31 | +except <exception class> as <name>: |
| 32 | + <except suite> |
| 33 | +... |
| 34 | +``` |
| 35 | + |
| 36 | +当`try`语句执行时,`<try suite>`总是会立即执行。`except`子句组只在`<try suite>`执行过程中的异常产生时执行。每个`except`子句指定了需要处理的异常的特定类。例如,如果`<exception class>`是`AssertionError`,那么任何继承自`AssertionError`的类实例都会被处理,标识符`<name> `绑定到所产生的异常对象上,但是这个绑定在`<except suite>`之外并不有效。 |
| 37 | + |
| 38 | +例如,我们可以使用`try`语句来处理异常,在异常发生时将`x`绑定为`0`。 |
| 39 | + |
| 40 | +```py |
| 41 | +>>> try: |
| 42 | + x = 1/0 |
| 43 | + except ZeroDivisionError as e: |
| 44 | + print('handling a', type(e)) |
| 45 | + x = 0 |
| 46 | +handling a <class 'ZeroDivisionError'> |
| 47 | +>>> x |
| 48 | +0 |
| 49 | +``` |
| 50 | + |
| 51 | +`try`语句能够处理产生在函数体重的异常,函数在`<try suite>`中调用。当异常产生时,控制流会直接跳到最近的`try`语句的能够处理该异常类型的`<except suite>`的主体中。 |
| 52 | + |
| 53 | +```py |
| 54 | +>>> def invert(x): |
| 55 | + result = 1/x # Raises a ZeroDivisionError if x is 0 |
| 56 | + print('Never printed if x is 0') |
| 57 | + return result |
| 58 | +>>> def invert_safe(x): |
| 59 | + try: |
| 60 | + return invert(x) |
| 61 | + except ZeroDivisionError as e: |
| 62 | + return str(e) |
| 63 | +>>> invert_safe(2) |
| 64 | +Never printed if x is 0 |
| 65 | +0.5 |
| 66 | +>>> invert_safe(0) |
| 67 | +'division by zero' |
| 68 | +``` |
| 69 | + |
| 70 | +这个例子表明,`invert`中的`print`表达式永远不会求值,反之,控制流跳到了`handler`中的`except`子句组中。将`ZeroDivisionError e`强制转为字符串会得到由`handler: 'division by zero'`返回的人类可读的字符串。 |
| 71 | + |
0 commit comments