捕获错误

捕获错误:try…except…finally…

这套机制的运行有点类似 if

try: 将可能出错的代码块放在里面 代码会在try里面运行,直达发生错误,立即终止运行

except 错误类型: 当try捕获到某个特定错误时,转跳到except并运行里面的代码。 如果没有发生错误则会被忽略 错误类型: ZeroDivisionError:除零错误 TypeError:类型错误 Exception :任意错误

finally: 当except运行完后,如果有finally,则会运行这部分

  1. print("start")
  2. try:
  3. print("发生错误之前")
  4. y = 5/0 # 分母为0的错误,try捕获到ZeroDivisionError
  5. print("发生错误之后")
  6. pass
  7. except SyntaxError: # 不是try捕获的错误类型
  8. print("A-报告错误")
  9. except ZeroDivisionError: # 是try捕获的错误类型,运行该部分
  10. print("B-报告错误")
  11. finally:
  12. print("错误处理完成")
  13. print("Done")
  14. #输出
  15. #=================================
  16. 发生错误之前
  17. B-报告错误
  18. 错误处理完成
  1. print("start")
  2. try:
  3. print("发生错误之前")
  4. y = 5/1 # 没有捕获到错误,继续运行
  5. print("发生错误之后")
  6. except ZeroDivisionError: # 跳过
  7. print("B-报告错误")
  8. finally: # 执行
  9. print("错误处理完成")
  10. print("Done")
  11. #输出
  12. #=================================
  13. start
  14. 发生错误之前
  15. 发生错误之后
  16. 错误处理完成

返回错误:except … as …

当except捕获到错误后,可让except把错误信息储存到一个变量内

except 错误类型 as 变量

  1. try:
  2. y = 5/1 # 没有捕获到错误,继续运行
  3. except ZeroDivisionError as e: # 跳过
  4. print("ZeroDivisionError:", e)
  5. #输出
  6. #=================================
  7. ZeroDivisionError division by zero

异常栈

假如我们不用try捕获异常,异常会从开始的位置一层一层的上抛,并记录下来 直到被最外层的python解释器捕获。并打印出来(打印出来的跟踪信息就是异常栈)

  1. class Name(object):
  2. def func(self):
  3. self.__function()
  4. def __function(self):
  5. y = 4/0
  6. obj = Name()
  7. obj.func()
  1. #输出异常栈
  2. #=============================================================
  3. Traceback (most recent call last):
  4. File "E:\Projects Files\Py_2020_12_05\PythonApplication2\PythonApplication2\play.py", line 9, in <module>
  5. obj.func()
  6. File "E:\Projects Files\Py_2020_12_05\PythonApplication2\PythonApplication2\play.py", line 3, in func
  7. self.__function()
  8. File "E:\Projects Files\Py_2020_12_05\PythonApplication2\PythonApplication2\play.py", line 6, in __function
  9. y = 4/0
  10. ZeroDivisionError: division by zero

保存记录:logging

如果用上述方法,有一个问题, 那就是只要遇到错误,整个程序就中止了。 如果想不让他中止用try,又不能返回异常栈怎么办?

Python内置logging模块,可以保存记录

  1. import logging
  2. print("开始处理异常")
  3. try:
  4. y = 5/0
  5. except Exception as e:
  6. logging.exception(e)
  7. print("异常处理完成")
  1. 开始处理异常
  2. ERROR:root:division by zero
  3. Traceback (most recent call last):
  4. File "E:\Projects Files\Py_2020_12_05\PythonApplication2\PythonApplication2\play.py", line 4, in <module>
  5. y = 5/0
  6. ZeroDivisionError: division by zero
  7. 异常处理完成

抛出错误

抛出错误:raise

有时候我们需要特意去抛出一个错误 可以用关键字raise

使用raise上抛错误,同样可以被捕获和跟踪

  1. def func(val):
  2. if val == 0:
  3. print("值为0开始抛出错误")
  4. raise ZeroDivisionError("val == %s" %val)
  5. else:
  6. print("值不为0不抛出错误")
  7. func(0)
  8. print("程序结束")
  1. #输出
  2. #=============================================================
  3. 值为0开始抛出错误
  4. Traceback (most recent call last):
  5. File "E:\Projects Files\Py_2020_12_05\PythonApplication2\PythonApplication2\play.py", line 7, in <module>
  6. func(0)
  7. File "E:\Projects Files\Py_2020_12_05\PythonApplication2\PythonApplication2\play.py", line 4, in func
  8. raise ZeroDivisionError("val == %s" %val)
  9. ZeroDivisionError: val == 0
  10. #=============================================================
  11. 当程序遇到raise后抛出错误终止运行了

如果没有遇到raise就不会抛出

  1. def func(val):
  2. if val == 0:
  3. print("值为0开始抛出错误")
  4. raise ZeroDivisionError("val == %s" %val)
  5. else:
  6. print("值不为0不抛出错误")
  7. func(10)
  8. print("程序结束")
  9. #输出
  10. #=============================================================
  11. 值不为0不抛出错误
  12. 程序结束

错误类:BaseException

错误也是一个类,也具有继承关系

所有的错误都继承于BaseException 基类可以捕获到子类的错误 子类不能捕获到基类的错误

  1. 错误继承关系表
  2. BaseException
  3. +-- SystemExit
  4. +-- KeyboardInterrupt
  5. +-- GeneratorExit
  6. +-- Exception
  7. +-- StopIteration
  8. +-- StopAsyncIteration
  9. +-- ArithmeticError
  10. | +-- FloatingPointError
  11. | +-- OverflowError
  12. | +-- ZeroDivisionError
  13. +-- AssertionError
  14. +-- AttributeError
  15. +-- BufferError
  16. +-- EOFError
  17. +-- ImportError
  18. | +-- ModuleNotFoundError
  19. +-- LookupError
  20. | +-- IndexError
  21. | +-- KeyError
  22. +-- MemoryError
  23. +-- NameError
  24. | +-- UnboundLocalError
  25. +-- OSError
  26. | +-- BlockingIOError
  27. | +-- ChildProcessError
  28. | +-- ConnectionError
  29. | | +-- BrokenPipeError
  30. | | +-- ConnectionAbortedError
  31. | | +-- ConnectionRefusedError
  32. | | +-- ConnectionResetError
  33. | +-- FileExistsError
  34. | +-- FileNotFoundError
  35. | +-- InterruptedError
  36. | +-- IsADirectoryError
  37. | +-- NotADirectoryError
  38. | +-- PermissionError
  39. | +-- ProcessLookupError
  40. | +-- TimeoutError
  41. +-- ReferenceError
  42. +-- RuntimeError
  43. | +-- NotImplementedError
  44. | +-- RecursionError
  45. +-- SyntaxError
  46. | +-- IndentationError
  47. | +-- TabError
  48. +-- SystemError
  49. +-- TypeError
  50. +-- ValueError
  51. | +-- UnicodeError
  52. | +-- UnicodeDecodeError
  53. | +-- UnicodeEncodeError
  54. | +-- UnicodeTranslateError
  55. +-- Warning
  56. +-- DeprecationWarning
  57. +-- PendingDeprecationWarning
  58. +-- RuntimeWarning
  59. +-- SyntaxWarning
  60. +-- UserWarning
  61. +-- FutureWarning
  62. +-- ImportWarning
  63. +-- UnicodeWarning
  64. +-- BytesWarning
  65. +-- ResourceWarning

https://docs.python.org/3/library/exceptions.html#exception-hierarchy


调试错误:

断言:assert

功能:当满足条件时,抛出错误 (类似 if 和 raise 的结合体)

特点: 相比if…raise,断言assert可以通过python解释器关闭,使其失效 (这时assert就等价于pass语句了) (assert会在Relsese阶段被关闭,但注意通常还是手动全部删掉比较好)

  1. 语法:
  2. assert 返回值是布尔的表达式 , [可选参数,一般放错误说明]
  1. assert False,"触发错误" # 类似与使用if...raise
  2. #if True:
  3. # raise AssertionError("触发错误")
  4. #输出
  5. #==================================
  6. Traceback (most recent call last):
  7. File "E:\play.py", line 1, in <module>
  8. assert False,"触发错误"
  9. AssertionError: 触发错误

错误日志

我参考了这篇博客:https://www.cnblogs.com/CJOKER/p/8295272.html

Logging:输出到控制

下面几个语句,和print( )类似 只不过,根据安全级别不同,可以控制是否输出(默认比warning低的不输出)

debug: 调试,打印所有信息,一般用于诊断问题 info: 正常运行输出的日志 warning: 目前运行正常,但有可能会出问题 error: 已经出现了一些问题 critical: 出现严重的问题,可能导致程序崩溃

  1. import logging
  2. logging.debug("A-Debug")
  3. logging.info("B-Info")
  4. logging.warning("C-Warning")
  5. logging.error("D-Error")
  6. logging.critical("E-Critiacl")
  1. #输出
  2. #==================================
  3. WARNING:root:C-Warning
  4. ERROR:root:D-Error
  5. CRITICAL:root:E-Critiacl

Logging:设置安全级别

如果希望输出安全等级低的info、debug等,可以使用basicConfig设置安全等级

  1. import logging
  2. logging.basicConfig(level=logging.DEBUG) # 设置安全级别
  3. logging.debug("A-Debug")
  4. logging.info("B-Info")
  5. logging.warning("C-Warning")
  6. logging.error("D-Error")
  7. logging.critical("E-Critiacl")
  1. #输出
  2. #==================================
  3. DEBUG:root:A-Debug
  4. INFO:root:B-Info
  5. WARNING:root:C-Warning
  6. ERROR:root:D-Error
  7. CRITICAL:root:E-Critiacl

配置输出format格式 %(levelno)s: 打印日志级别的数值 %(levelname)s:: 打印日志级别名称 %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]

%(filename)s: 打印当前执行程序名

%(funcName)s: 打印日志的当前函数

%(lineno)d: 打印日志的当前行号

%(asctime)s: 打印日志的时间

%(thread)d: 打印线程ID

%(threadName)s: 打印线程名称

%(process)d: 打印进程ID

%(message)s: 打印日志信息

  1. import logging
  2. logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
  3. logging.debug("A-Debug")
  4. logging.info("B-Info")
  5. logging.warning("C-Warning")
  6. logging.error("D-Error")
  7. logging.critical("E-Critiacl")
  1. 2021-02-07 20:00:05,008 - play.py[line:4] - DEBUG: A-Debug
  2. 2021-02-07 20:00:05,008 - play.py[line:5] - INFO: B-Info
  3. 2021-02-07 20:00:05,009 - play.py[line:6] - WARNING: C-Warning
  4. 2021-02-07 20:00:05,009 - play.py[line:7] - ERROR: D-Error
  5. 2021-02-07 20:00:05,009 - play.py[line:8] - CRITICAL: E-Critiacl

Pdb:跟踪程序

如果程序是在IDE中测试的,我们可以直接设置断点进行跟踪 QQ截图20210207202049.png

但如果是在控制台中,就不能使用IDE的断点功能了 此时,可以使用pdb模块中的pdb.set_trace( )方法设置断点 每次输入n,会自动执行下一句,返回跟踪信息,并再次暂停

  1. import pdb
  2. print("output-A")
  3. print("output-B")
  4. pdb.set_trace()
  5. print("output-C")
  6. print("output-D")
  1. #输出
  2. #==================================
  3. output-A
  4. output-B
  5. > e:\projects files\py_2020_12_05\pythonapplication2\pythonapplication2\play.py(5)<module>()
  6. -> print("output-C")
  7. (Pdb) n
  8. output-C
  9. > e:\projects files\py_2020_12_05\pythonapplication2\pythonapplication2\play.py(6)<module>()
  10. -> print("output-D")
  11. (Pdb) n
  12. output-D
  13. --Return--
  14. > e:\projects files\py_2020_12_05\pythonapplication2\pythonapplication2\play.py(6)<module>()->None
  15. -> print("output-D")
  16. (Pdb) n
  17. --Call--
  18. Exception ignored in: <async_generator object _ag at 0x00000267E65A41E8>
  19. Traceback (most recent call last):
  20. File "D:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\types.py", line 27, in _ag
  21. File "D:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\bdb.py", line 53, in trace_dispatch
  22. File "D:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\bdb.py", line 85, in dispatch_call
  23. File "D:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\pdb.py", line 251, in user_call
  24. File "D:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\pdb.py", line 343, in interaction
  25. AttributeError: 'NoneType' object has no attribute '_previous_sigint_handler'