这里的错误和异常不是特指语法错误,而是指程序在运行时发生的错误。即使语句或表达式在语法上是正确的,当尝试执行它时也可能会导致错误。这个错误可能是由于输入数据的问题,运行环境的问题,还可能是参数配置的问题等等,
随着代码编写的多了,应用环境的变化,各种各样的奇奇怪怪问题都会出现,我们会开始意识到,错误处理的重要性。毕竟比运行中断更可怕的,任务以错误的方式运行完了。 随着处理的问题情况增加,我们必须要开始有意识的对代码进行一些错误处理。来增强代码的鲁棒性/异常识别能力。
try except
基础版本使用 try except
我们更多的可能是类似if else
的用法,重点关注try
的代码能不能成功运行,但是实际上except 是可以识别不同的异常类型的,对应的我们也可以进行不同的处理。
1 | import sys |
python的标准异常类型:
异常名称 | 描述 |
---|---|
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
Exception | 常规错误的基类 |
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
ImportError | 导入模块/对象失败 |
LookupError | 无效数据查询的基类 |
IndexError | 序列中没有此索引(index) |
KeyError | 映射中没有这个键 |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 尚未实现的方法 |
SyntaxError | Python 语法错误 |
IndentationError | 缩进错误 |
TabError | Tab 和空格混用 |
SystemError | 一般的解释器系统错误 |
TypeError | 对类型无效的操作 |
ValueError | 传入无效的参数 |
UnicodeError | Unicode 相关的错误 |
UnicodeDecodeError | Unicode 解码时的错误 |
UnicodeEncodeError | Unicode 编码时错误 |
UnicodeTranslateError | Unicode 转换时错误 |
Warning | 警告的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
FutureWarning | 关于构造将来语义会有改变的警告 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
SyntaxWarning | 可疑的语法的警告 |
UserWarning | 用户代码生成的警告 |
raise(引发异常)
raise
语句允许程序员强制发生指定的异常。 raise
的唯一参数指示要引发的异常。这必须是异常实例或异常类(从 BaseException 派生的类,例如 Exception 或其子类之一)。如果传递异常类,它将通过不带参数调用其构造函数来隐式实例化:例如:
1
2raise ValueError() # 不传递参数的异常类,会进行隐式实例化
raise NameError('HiThere') # 传递参数将异常类进行实例化。
定义清理操作(final)
try
语句还有另一个可选子句,旨在定义在所有情况下都必须执行的清理操作。如果存在 finally
子句,则 finally
子句将作为 try
语句完成之前的最后一个任务执行。无论 try
语句是否产生异常, finally
子句都会运行。在实际应用程序中, finally 子句对于释放外部资源(例如文件或网络连接)非常有用,无论资源的使用是否成功。示例如下:
1 | def divide(x, y): |
以下几点讨论发生异常时更复杂的情况:
- 如果在执行 try 子句期间发生异常,则该异常可以由 except 子句处理。如果 except 子句未处理异常,则在执行 finally 子句后将重新引发异常。
- 执行 except 或 else 子句期间可能会发生异常。同样,在执行 finally 子句后会重新引发异常。
- 如果 finally 子句执行 break 、 continue 或 return 语句,则不会重新引发异常。
- 如果 try 语句到达 break 、 continue 或 return 语句,则 finally 子句将在之前执行到 break 、 continue 或 return 语句的执行。
- 如果 finally 子句包含 return 语句,则返回值将是 finally 子句的 return 语句中的值,而不是值来自 try 子句的 return 语句。
丰富异常
当创建异常以便引发时,通常使用描述已发生的错误的信息对其进行初始化。在某些情况下,在捕获异常后添加信息很有用。为此,异常有一个方法 add_note(note) ,它接受一个字符串并将其添加到异常的注释列表中。标准回溯渲染包括异常之后的所有注释(按添加顺序)1
2
3
4
5
6
7
8
9
10
11
12try:
raise TypeError('bad type')
except Exception as e:
e.add_note('Add some information')
e.add_note('Add some more information')
raise
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: bad type
Add some information
Add some more information