一、什么是错误与异常

错误

一般指程序编写有误,语法不规范而导致程序无法运行,这样的称为错误;

异常

程序无语法问题,可以正常运行,但在运行过程中出现的错误,例如:值转换错误(int('a'))、除数不能为0等,这样的问题称为异常;
当发生异常时,程序会抛出这个异常并且停止运行,因此为了更快定位问题、避免程序在不需要停止的地方停止允许,我们应该对异常进行恰当的捕获并且抛出,根据实际场景选择是停止运行还是继续往下走其余逻辑。

二、如何捕获并抛出异常

捕获异常的基本格式

在Python中,处理异常会使用try-except语句,这个语句还有两个可选的子句:else和finally,整体基本流程如下:

python schedule中异常停止 python错误和异常处理_代码块

第一种最基础的格式,try-except

try:
    statements
except [errortype]:
    statements
except [errortype]:
    statements

此为Python处理异常的最基本结构:try分支中的语句为可能会出现异常的代码块,except为捕获异常并进行处理的语句--可以有多个,但只会执行一个except分支。except后通常为要处理的预见可能会出现的异常类型,异常类型可以为一个或多个--为多个时使用元组 (RuntimeError, TypeError, NameError) ,最后一个except可以省略异常名称,将异常信息作为意外异常进行打印;
处理流程如下:

  • 执行了try分支中的语句,若未触发异常,则将try分支中代码块执行完毕后,代码忽略except分支,继续往下执行。若触发了异常,则执行except分支;
  • 触发了异常,执行except分支,通过触发的异常类型来与except后的异常类型来进行匹配,若成功匹配,则执行该except分支下的代码;

第二种,try-except-else,可选语句else

try:
    statements
except ......:
    statements
else:
    statements
  • else语句为可选语句,若写,则需要放在所有的except语句之后,可以理解为:若发生异常--找到相匹配的except分支并执行--相反、未发生异常,则执行else分支;
  • else分支用来执行未发生异常时需要继续执行的代码块,我们可以将认为有可能出现异常的代码块放在try分支中,将不太可能出现异常的代码块放在else分支下;

第三种,try-except-finally,可选语句finally:

try:
    statements
except ......:
    statements
finally:
    statements
  • finally语句为可选语句,意为最终,是try-except-[else]-[finally]结构中,最终的部分,是无论是否发生异常,都会执行的分支;
  • try-except-[else]-[finally]结构中,各子句的顺序需要遵循此顺序;
  • 如果在try子句中发生了异常(或者在 except 和 else 子句里),但没有被任何except语句捕获,那么这个异常会在执行完 finally 分支后抛出。

assert语句触发异常

  • assert断言 语句后跟表达式,当表达式结果为True时,不做任何操作;当表达式结果为False时,触发 AssertionError 异常。
assert 1 == 2

raise语句抛出异常

  • raise语句后为一个可选参数;
  • 当填写此参数时,此参数必须是一个异常类,也就是 Exception 的子类;
a = 3
b = 0
if b == 0:
    raise ZeroDivisionError('除数不能为0')
print(a / b)
  • raise语句后若不写参数,则直接抛出当前异常。
try:
    a = 3 / 0
except ZeroDivisionError:
    print('error!')
    raise
-----------
Traceback (most recent call last):
  File "/Users/lxc/Desktop/codeSpace/myCode/pyCode/all_study_practice/sth_temps.py", line 835, in <module>
    a = 3 / 0
ZeroDivisionError: division by zero
error!
  • raise语句是在可预见有异常发生的情况下,手动抛出某异常,而except语句是捕获异常并进行处理。若except捕获异常后却并没有进行抛出,则可以使用单独的、不添加参数的 raise语句抛出当前异常;若在except分支中使用 raise [ErrorType]再抛出异常,则会报错 During handling of the above exception, another exception occurred,并且会影响真正需要抛出的异常信息。若在raise抛出的异常中未添加有效的额外错误信息,则此种写法并没有多大意义。
try:
    a = 3 / 0
except ZeroDivisionError:
    print('error!')
    raise ZeroDivisionError('除数不能为0')
-----------
error!
Traceback (most recent call last):
  File "/Users/lxc/Desktop/codeSpace/myCode/pyCode/all_study_practice/sth_temps.py", line 835, in <module>
    a = 3 / 0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/lxc/Desktop/codeSpace/myCode/pyCode/all_study_practice/sth_temps.py", line 838, in <module>
    raise ZeroDivisionError('除数不能为0')
ZeroDivisionError: 除数不能为0

三、用户自定义异常

  • 用户可以通过继承 Exception 类来自定义异常。
class MyError(Exception):
    pass
  • 如果内置异常已经可以满足需要,建议使用内置异常。

四、常见的异常类型有哪些

  • 内置异常的层次结构如下:
BaseException  ——所有异常的基类,最基础的异常类
 +-- SystemExit  ——解释器请求退出
 +-- KeyboardInterrupt  ——用户中断执行
 +-- GeneratorExit  ——生成器发生异常来通知退出
 +-- Exception  ——常规错误的基类
      +-- StopIteration  ——迭代器没有更多的值
      +-- StandardError  ——所有内建标准异常的基类
      |    +-- BufferError
      |    +-- ArithmeticError  ——所有数值计算错误的基类
      |    |    +-- FloatingPointError  ——浮点计算错误
      |    |    +-- OverflowError  ——数值运算超出最大限制
      |    |    +-- ZeroDivisionError  ——除(或取模)0
      |    +-- AssertionError  ——断言失败
      |    +-- AttributeError  ——对象没有这个属性
      |    +-- EnvironmentError  ——操作系统错误的基类
      |    |    +-- IOError  ——输入/输出操作失败
      |    |    +-- OSError  ——操作系统错误
      |    |         +-- WindowsError (Windows)  ——系统调用失败
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
      |    +-- ImportError  ——导入模块/对象失败
      |    +-- LookupError  ——无效数据查询的基类
      |    |    +-- IndexError  ——序列中没有此索引
      |    |    +-- KeyError  ——映射中没有这个键
      |    +-- MemoryError  ——内存溢出错误
      |    +-- NameError  ——未声明/初始化对象
      |    |    +-- UnboundLocalError
      |    +-- ReferenceError
      |    +-- RuntimeError  ——一般的运行时错误
      |    |    +-- NotImplementedError
      |    +-- SyntaxError  ——Python语法错误
      |    |    +-- IndentationError  ——缩进错误
      |    |         +-- TabError  ——Tab 和空格混用
      |    +-- SystemError
      |    +-- TypeError  ——对类型无效的操作
      |    +-- ValueError  ——传入无效的参数
      |         +-- UnicodeError  ——Unicode相关的错误
      |              +-- UnicodeDecodeError  ——Unicode解码时的错误
      |              +-- UnicodeEncodeError  ——Unicode编码时的错误
      |              +-- UnicodeTranslateError  ——Unicode转换时的错误
      +-- Warning  ——警告的基类
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
       +-- ImportWarning
       +-- UnicodeWarning
       +-- BytesWarning
  • 从层级结构上来看,BaseException是所有异常的基类,Exception继承自BaseExceptionBaseException除了包含Exception外还包含另外三个异常,而这另外三个异常属于更高级别的异常,合理的做法是交给Python解释器进行处理。因此我们在要捕获通用的异常时,最好的做法是使用Exception来进行匹配。