错误和异常
错误
错误分为两种,一种是代码的语法错误,这类错误会被 Python 解释器的语法检测识别到,必须在程序执行前就进行修正。
1 | # 语法错误一 |
另一种属于程序的逻辑上的错误。比如数据类型的转换:
1 | # 比如输入为空,或者输入的不是数字 |
或是数学运算:
1 | 1 / 0 res1 = |
异常
异常指的就是就是程序运行时发生错误的信号,在 Python 中错误触发的异常如下:
在 Python 中不同的异常可以用不同的类型(Python 中统一了类与类型,类型即类)去标识,不同的类对象标识不同的异常,一个异常标识一种错误。
1 | 'egon','aa'] l=[ |
常用的异常如下:
- AttributeError:试图访问一个对象没有的属性,比如
foo.x
,但是foo
没有属性x
- IOError:输入/输出异常;基本上是无法打开文件
- ImportError:无法引入模块或包;基本上是路径问题或名称错误
- IndentationError:语法错误(的子类);代码没有正确对齐
- IndexError:下标索引超出序列边界,比如当
x
只有三个元素,却试图访问x[5]
- KeyError:试图访问字典里不存在的键
- KeyboardInterrupt:
Ctrl+C
被按下 - NameError:使用一个还未被赋予对象的变量
- SyntaxError:Python 代码语法错误,代码不能编译
- TypeError:传入对象类型与要求的不符合
- UnboundLocalError:试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致编写者以为正在访问它
- ValueError:传入一个调用者不期望的值,即使值的类型是正确的
异常处理
异常发生之后,异常之后的代码就不执行了。
Python 解释器检测到错误,触发异常(也允许程序员自己触发异常)。程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关),如果捕捉成功则进入另外一个处理分支,执行为其定制的逻辑,使程序不会崩溃,这就是异常处理。异常处理机制可以增强程序的健壮性与容错性。
try … except
Python 为每一种异常定制了一个类型,然后提供了一种特定的语法结构用来进行异常处理。一个基本的异常处理语法如下:
1 | try: |
异常类型只能用来处理指定的异常情况,如果遇到了非指定异常则无法处理:
1 | # 未捕获到异常,程序直接报错 |
使用异常处理的多分支可以针对不同的异常,进行不同的处理:
1 | s1 = 'hello' |
在 Python 的异常中,Exception
可以捕获任意异常。但这意味着在处理所有异常时都使用同一个逻辑去处理,这里说的逻辑即当前 expect
下面跟的代码块:
1 | s1 = 'hello' |
finally
如果存在 finally
,它将进行清理工作。无论异常与否,try
子句会被执行,包括任何 except
和 else
子句。
1 | s1 = 'hello' |
如果在这些子句中发生任何未处理的异常,该异常会被临时保存。 finally
子句将被执行。 如果存在被保存的异常,它会在 finally
子句的末尾被重新抛出异常。
1 | s1 = 'hello' |
如果 finally
子句执行了 return
或 break
语句,被保存的异常会被丢弃:
1 | def func(): |
在 finally
子句执行期间,程序不能获取异常信息。当 return
, break
或 continue
语句在一个 try...finally
语句的 try
子句体中被执行时,finally
子句也会 “在离开时” 被执行。函数的返回值是由最后被执行的 return
语句所决定的。 由于 finally
子句总是被执行,因此在 finally
子句中被执行的 return
语句总是最后被执行的:
1 | def func(): |
raise
使用 raise 语句将会主动触发异常:
1 | try: |
自定义异常
1 | class myException(BaseException): |
什么时候用异常处理
在编写 Python 程序时,try...except
应该尽量少用,因为它本身就是附加给程序的一种异常处理的逻辑,与代码主要工作是没有关系的。并且还会导致代码可读性变差。只有在有些异常无法预知的情况下,才应该加上 try...except
,其他的逻辑错误应该尽量修正。