调试 常用的方法有:
print, 仅作临时测试, 而且还要删除.
assert, 同print, 无明显优势.
logging, 推荐使用. 可选级别, 可选输出方式, 适用于各种情况的调试.
pdb 以及 基于pdb的图形化工具.
python的IDE, 如PyCharm(推荐), eclipse+PyDev
logging 简单使用 import loggingif __name__ == "__main__" : '''默认日志输出为终端, 设置日志等级, DEBUG=LEVEL10, 优先级最低''' logging.basicConfig(level=logging.DEBUG) '''更多设置''' logging.debug('DEBUG message' ) logging.info('INFO message' ) logging.warn('WARN message' ) logging.error('ERROR message' ) logging.critical('CRITICAL message' )
自定义显示格式 日志输出到 logger.log
import loggingif __name__ == "__main__" : '''设置显示格式, 日志输出到文件''' logging.basicConfig(level=logging.DEBUG, format ='%(asctime)s %(filename)-s[%(lineno)d] %(levelname)-8s: %(message)s' , filename='logger.log' , filemode='w' ) logging.debug('This is debug message' ) logging.info('This is info message' ) logging.warning('This is warning message' )
日志输出到 logger.log
以及终端
import loggingif __name__ == "__main__" : logging.basicConfig(level=logging.DEBUG, format ='%(asctime)s %(filename)s[%(lineno)d] %(levelname)-8s: %(message)s' , filename='logger.log' , filemode='w' ) ''' 定义一个StreamHandler,将INFO级别或更高的日志信息打印到标准错误,并将其添加到当前的日志处理对象 ''' console = logging.StreamHandler() console.setLevel(logging.INFO) formatter = logging.Formatter('%(levelname)-8s: %(message)s' ) console.setFormatter(formatter) logging.getLogger('' ).addHandler(console) logging.debug('This is debug message' ) logging.info('This is info message' ) logging.warning('This is warning message' )
使用文件配置 [loggers] keys=root [logger_root] level=DEBUG handlers=hand01,hand02 [handlers] keys=hand01,hand02,hand03 [handler_hand01] class=StreamHandler level=DEBUG formatter=form01 args=(sys.stderr,) [handler_hand02] class=FileHandler level=INFO formatter=form01 args=('logging.log' , 'w' ) [handler_hand03] class=handlers.RotatingFileHandler level=INFO formatter=form01 args=('logging.log' , 'a' , 10 *1024 *1024 , 5 ) [formatters] keys=form01 [formatter_form01] format =%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)-8s: %(message)s
import loggingif __name__ == "__main__" : from logging.config import fileConfig fileConfig("logging.conf" ) logging.debug('This is debug message' ) logging.info('This is info message' ) logging.warning('This is warning message' )
更多应用参考手册
pdb 进入调试模式 python -m pdb example.py
$ python -m pdb example.py (Pdb)
pdb 常用命令
# 断点 (Pdb) b 10 # 断点设置在当前文件的第10行 (Pdb) tbreak 10 # temp break, 临时断点, 执行后会自动删除 (Pdb) b my.py:20 # 断点设置到 my.py第20行 (Pdb) b # break, 查看断点编号 (Pdb) cl 2 # clear, 删除第2个断点 (Pdb) disable 2 # 禁用第2个断点 (Pdb) enable 2 # 使能第2个断点 (Pdb) ignore 2 10 # 略过第2个断点10次, 循环调试特别有用! (Pdb) condition 2 (i>10) # 条件为真时,使能断点 # 运行 (Pdb) n # next, 单步运行 (Pdb) s # step, 进入方法 (Pdb) r # return, 返回上级方法 (Pdb) c # continue, 跳到下个断点 # 查看 (Pdb) p param # print, 查看当前 变量值 (Pdb) l # list, 查看运行到某处代码 (Pdb) a # args, 查看全部栈内变量 (Pdb) w # where, 堆栈信息 # 其它 (Pdb) h # help, 帮助 (Pdb) q # quit, 退出调试
使用alias设置别名, 可大大提高调试速度!将下述文件存储为 .pdbrc
, 然后放在系统目录 ~
或 项目目录下, pdb会自动加载.
alias p_ for k in sorted (%1. keys()): print "%s%-15s= %-80.80s" % ("%2" ,k,repr (%1 [k])) alias pi p_ %1. __dict__ %1. alias ps pi self alias pl p_ locals () local: alias nl n;;l alias sl s;;l alias gl tbreak %*;;c %*;;l alias g1 n;;l alias g2 n;;n;;l alias g3 n;;n;;n;;l alias g4 n;;n;;n;;n;;l alias g5 n;;n;;n;;n;;n;;l alias g6 n;;n;;n;;n;;n;;n;;nl alias g7 n;;n;;n;;n;;n;;n;;n;;l alias g8 n;;n;;n;;n;;n;;n;;n;;n;;l alias g9 n;;n;;n;;n;;n;;n;;n;;n;;n;;l alias uu u;;u alias uuu u;;u;;u alias uuuu u;;u;;u;;u alias uuuuu u;;u;;u;;u;;u alias dd d;;d alias ddd d;;d;;d alias dddd d;;d;;d;;d alias ddddd d;;d;;d;;d;;d
查看函数调用 使用如下的装饰器, 即可观察该函数被调用的情况
def findcaller (func ): def wrapper (*args, **kwargs ): import sys f = sys._getframe() filename = f.f_back.f_code.co_filename lineno = f.f_back.f_lineno print '######################################' print '{}, args: {}, {}' .format (func, args, kwargs) print 'called by {}, line {}' .format (filename, lineno) print '######################################' func(*args, **kwargs) return wrapper
@findcaller def hello (name='world' ): print "hello" , name if __name__ == "__main__" : hello('DRA&PHO' )
测试 doctest 简单的函数测试个人比较喜欢使用doctest, 因为一举两得, 即可以做测试案例, 又是极好的代码注释和范例 输出和预期一致时, 没有任何提醒. 输出和预期不一致时, 就会弹出错误.
def hello (name='world' ): """ >>> hello() hello world >>> hello('DRA&PHO') hello, DRA&PHO """ print "hello" , name if __name__ == '__main__' : import doctest doctest.testmod()
其它
参考资料
原创于 DRA&PHO