《Python编程实训快速上手》第九天--调试技巧
一、抛异常
异常类型分为两类,第一类是Python自带的异常类型(见《Python编程快速上手》第一天---前三章打基础),第二类是自定义异常。
面对自定义异常类型,使用raise抛异常,类型值默认为Exception:
raise Exception("xxxxxxx")
raise
关键字。- 对
Exception()
函数的调用。- 传递给
Exception()
函数的字符串,包含有用的错误信息。
def boxPrint(symbol, width, height):if len(symbol) != 1:❶ raise Exception('Symbol must be a single character string.')if width < <= 2:❷ raise Exception('Width must be greater than 2.')if height < <= 2:❸ raise Exception('Height must be greater than 2.')print(symbol * width)for i in range(height - 2):print(symbol + (' ' * (width - 2)) + symbol) print(symbol * width)for sym, w, h in (('*', 4, 4), ('O', 20, 5), ('x', 1, 3), ('ZZ', 3, 3)):try:boxPrint(sym, w, h)❹ except Exception as err:❺ print('An exception happened: ' + str(err))
当前程序中使用了except
语句的except Exception as err
形式。如果boxPrint()
返回一个Exception
对象❶❷❸,那么这条except
语句就会将该对象保存在名为err
的变量中。Exception
对象可以传递给str()
以将它转换为一个字符串,从而得到对用户友好的错误信息 。
二、取得回溯字符串
如果Python遇到错误,它就会生成一些错误信息,称为“回溯”。错误信息组成的序列称为“调用栈”。顾名思义,报错信息最下边是报错内容,往上是层层函数调用记录,显示了代码的执行路径。
导入Python的traceback
模块,调用traceback.format_ exc()
可以得到其字符串形式,该形式可用于写入文件中。
三、断言
“断言”是健全性检查,用于确保代码没有做什么明显错误的事情。
assert
关键字。- 条件(即求值为
True
或False
的表达式)。- 逗号。
- 当条件为
False
时显示的字符串。
程序开发时使用断言,因为断言发生错误会直接崩溃。
程序正常运行中抛出异常,处理可能遇到的那些错误(如文件没有找到,或用户输入了无效的数据)。不应使用assert
语句来引发异常,因为用户可以选择关闭异常。
四、日志
1、使用logging模块
要启用logging
模块以在程序运行时将日志消息显示在屏幕上,请将下面的代码复制到程序顶部:
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s- %(message)s')
之后使用logging.debug()
函数输出日志消息,这个debug()
函数将调用basicConfig()以
输出一行信息。这行信息的格式是我们在basicConfig()
函数中指定的。
例如:输出n的阶乘
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s- %(message)s')
logging.debug('Start of program')def factorial(n):logging.debug('Start of factorial(%s%%)' % (n))total = 1for i in range(1,n + 1):total *= ilogging.debug('i is ' + str(i) + ', total is ' + str(total))logging.debug('End of factorial(%s%%)' % (n))return totalprint(factorial(5))
logging.debug('End of program')
白色字体是print()输出结果,红色字体是日志内容
2、不可使用print()代替
不使用print()是因为在调试完成后,你需要花很多时间从代码中清除每条日志消息的print()
调用。
使用日志消息的好处在于,你可以在程序中想加多少就加多少,稍后只要加入一次logging.disable()
调用就可以禁止日志,不像print()
需逐条清除。
3、日志级别
级别 | 日志函数 | 描述 |
DEBUG | logging.debug() | 最低级别。用于小细节。通常只有在诊断问题时,你才会关心这些消息 |
INFO | logging.info() | 用于记录程序中一般事件的信息,或确认一切工作正常 |
WARNING | logging.warning() | 用于表示可能的问题,它在当前不会阻止程序的工作,但将来可能会 |
ERROR | logging.error() | 用于记录错误,它导致程序做某事失败 |
CRITICAL | logging.critical() | 最高级别。用于表示致命的错误,它导致或将会导致程序完全停止工作 |
划分日志级别的好处在于,可以改变希望看到的日志消息的优先级。传入level
关键字参数级别越低,能看到的日志消息越多。
4、禁用日志
5、将日志记录到文件
logging.basic Config()
函数可以接收filename
关键字参数 。
import logging
logging.basicConfig(filename='myProgramLog.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')