异常就是运行期检测到的错误。计算机语言针对可能出现的错误定义了异常类型,某种错误引发对应的异常时,异常处理 程序将被启动,从而恢复程序的正常运行。

准标常异

  1. BaseException 所有异常的类基
  2. Exception 常规异常的类基
  3. StandardError 所有的内建标准异常的基类
  4. ArithmeticError 所有数值计算异常的基类
  5. FloatingPointError 浮点计算异常
  6. OverflowError 数值运算超出最大限制
  7. ZeroDivisionError 除数为零
  8. AssertionError断言语句(assert)失败
  9. AttributeError 尝试访问未知的对象属性
  10. EOFError 没有内建输入,到达EOF标记
  11. EnvironmentError 操作系统异常的基类
  12. IOError 输入/输出操作失败
  13. OSError 操作系统产生的异常(例如打开一个不存在的文件)
  14. WindowsError 系统调用失败
  15. ImportError 导入模块失败的时候
  16. KeyboardInterrupt 用户中断执行
  17. LookupError 无效数据查询的基类
  18. IndexError 索引超出序列的范围
  19. KeyError 字典中查找一个不存在的关键字
  20. MemoryError 内存溢出(可通过删除对象释放内存)
  21. NameError 尝试访问一个不存在的变量
  22. UnboundLocalError 访问未初始化的本地变量
  23. ReferenceError 弱引用试图访问已经垃圾回收了的对象
  24. RuntimeError 一般的运行时异常
  25. NotImplementedError 尚未实现的方法
  26. SyntaxError 语法错误导致的异常
  27. IndentationError 缩进错误导致的异常
  28. TabError Tab和空格混用
  29. SystemError 一般的解释器系统异常
  30. TypeError 不同类型间的无效操作
  31. ValueError 传入无效的参数
  32. UnicodeError Unicode相关的异常
  33. UnicodeDecodeError Unicode解码时的异常
  34. UnicodeEncodeError Unicode编码错误导致的异常
  35. UnicodeTranslateError Unicode转换错误导致的异常

异常体系内部有层次关系,Python异常体系中的部分关系如下所示:

准标告警

  1. Warning 警告的基类
  2. DeprecationWarning 关于被弃用的特征的警告
  3. FutureWarning 关于构造将来语义会有改变的警告
  4. UserWarning 用户代码生成的警告
  5. PendingDeprecationWarning 关于特性将会被废弃的警告
  6. RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
  7. SyntaxWarning 可疑语法的警告
  8. ImportWarning 用于在导入模块过程中触发的警告
  9. UnicodeWarning 与Unicode相关的警告
  10. BytesWarning 与字节或字节码相关的警告

try-except

try 语句按照如下方式工作:

  1. 首先,执行 try 子句(在关键字 try 和关键字 except 之间的语句)
  2. 如果没有异常发生,忽略 except 子句, try 子句执行后结束。
  3. 如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。
  4. 如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行。
  5. 最后执行 try 语句之后的代码。
  6. 如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。
  1. try:
  2. f = open('test.txt')
  3. print(f.read()) f.close()
  4. except OSError:
  5. print('打开文件出错')
  6. # 打开文件出错
  7. #---------------------------------------
  8. try:
  9. f = open('test.txt')
  10. print(f.read())
  11. f.close()
  12. except OSError as error:
  13. print('打开文件出错\n原因是: ' + str(error))
  14. # 打开文件出错
  15. # 原因是: [Errno 2] No such file or directory: 'test.txt'

一个 try 语句可能包含多个 except 子句,分别来处理不同的特定的异常。最多只有一个分支会被执行。使用多个 except 代码块时,必须坚持对其规范排序,要从最具针对性的异常到最通用的异常。

  1. try:
  2. int("abc")
  3. s = 1 + '1'
  4. f = open('test.txt')
  5. print(f.read())
  6. f.close()
  7. except OSError as error:
  8. print('打开文件出错\n原因是:' + str(error))
  9. except TypeError as error:
  10. print('类型出错\n原因是: ' + str(error))
  11. except ValueError as error:
  12. print('数值出错\n原因是: ' + str(error))
  13. # 数值出错
  14. # 原因是: invalid literal for int() with base 10: 'abc'

一个 except 子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组。

  1. try:
  2. s = 1 + '1'
  3. int("abc")
  4. f = open('test.txt')
  5. print(f.read())
  6. f.close()
  7. except (OSError, TypeError, ValueError) as error:
  8. print('出错了!\n原因是: ' + str(error))
  9. # 出错了!
  10. # 原因是: unsupported operand type(s) for +: 'int' and 'str'

try-except-finally

不管 try 子句里面有没有发生异常, finally 子句都会执行。
如果一个异常在 try 子句里被抛出,而又没有任何的 except 把它截住,那么这个异常会在 finally 子句执行后被抛出。

  1. def divide(x, y):
  2. try:
  3. result = x / y
  4. print("result is", result)
  5. except ZeroDivisionError:
  6. print("division by zero!")
  7. finally:
  8. print("executing finally clause")
  9. divide(2, 1)
  10. # result is 2.0
  11. # executing finally clause
  12. divide(2, 0)
  13. # division by zero!
  14. # executing finally clause
  15. divide("2", "1")
  16. # executing finally clause
  17. # TypeError: unsupported operand type(s) for /: 'str' and 'str'

try-except-else

如果在 try 子句执行时没有发生异常,Python 将执行 else 语句后的语句。

  1. try:
  2. fh = open("testfile", "w")
  3. fh.write("这是一个测试文件,用于测试异常!!")
  4. except IOError:
  5. print("Error: 没有找到文件或读取文件失败")
  6. else: print("内容写入文件成功")
  7. fh.close()
  8. # 内容写入文件成功

raise

Python 使用 raise 语句抛出一个指定的异常。

  1. try:
  2. raise NameError('HiThere')
  3. except NameError:
  4. print('An exception flew by!')
  5. # An exception flew by!

assert

assert 是程序员用于保证程序的正确性,不是用于检查使用者输入参数是否合法。换言之,assert 可以简单的理解为程序员的 debug 工具,正式的代码中应该使用 raise 来检查用户输入是否正确,如下:

  1. # assert
  2. assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, minimum)
  3. # raise
  4. if minimum < 1024:
  5. raise ValueError('Minimum port must be at least 1024, not %d.' % (minimum,))