Python中Debug有很多种方式,比如直接用ide去 pydebug,或者命令行去debug。这里介绍Python调试代码的4种方法:print、log、pdb、PyCharm的debug,分别有什么优缺点。

一.使用ide debug

PyCharm提供的debug功能,也提供了单步调试代码的功能。

优点:提供图形化界面,很直观;功能强大;不需要修改代码
缺点:依赖ide

二. print

用print调试代码是最简单的一种方法,也很常用,大部分人都掌握这种技巧。

在代码中合适的地方插入语句,可以是输出提示语句或者输出某些变量。

优点:比较直观,使用简单

缺点:需要入侵代码,也就是要修改代码

三. logging

就是利用logging模块,在代码合适的地方插入输出log语句,把合适的信息输出到log文件中,通过查看log文件分析代码的执行情况。

优点:logging模块可以指定输出格式和内容(可以输出时间,代码的行号,当前运行程序的名称、当前运行的函数名称、进程ID等等),因此能获得更精确的调试信息,应用场景更广泛,可以应用于生产环境。

缺点:需要入侵代码,也就是要修改代码;使用更复杂。

import os
import time
import logging

root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
log_dir = os.path.join(root_dir, "logs")
if not os.path.exists(log_dir):
    os.mkdir(log_dir)

my_logging = logging.getLogger('bktest')  # 创建日志收集器
my_logging.setLevel('DEBUG')  # 设置日志收集级别
ch = logging.StreamHandler()  # 输出到控制台
# my_logging.setLevel('INFO')  # 设置日志输出级别
my_logging.addHandler(ch)  # 对接,添加渠道

# 创建文件处理器fh,log_file为日志存放的文件夹
log_file = os.path.join(log_dir, "{}_log".format(time.strftime("%Y-%m-%d", time.localtime())))
fh = logging.FileHandler(log_file, encoding="UTF-8")
my_logging.addHandler(fh)  # 对接,添加渠道

# 指定输出的格式
formatter = logging.Formatter('%(asctime)s-%(levelname)s-%(filename)s-%(name)s-日志信息-%(message)s')
# 规定日志输出的时候按照formatter格式来打印
ch.setFormatter(formatter)
fh.setFormatter(formatter)

my_logging.debug("这是一个debug的信息")
my_logging.info("这是一个info的信息")
my_logging.warning("这是一个warning的信息")
my_logging.error("这是一个error的信息")
my_logging.critical("这是一个critical的信息")

s = list()
for i in range(10):
    my_logging.debug("test")
    s.append(i)
print(s)

四. pdb

debug是编码是非常重要的调试技巧,通过在运行过程中设置断点,帮助开发人员更好的理解运行过程。

Python中debug不像JAVA或者C++那样在IDE中设置断点那么直观。

下面记录一下另外一种方式,直接以命令行的方式debug:

pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点、单步调试、进入函数调试、查看当前代码、查看栈片段、动态改变变量的值等。

优点:功能强大,使用简单

缺点:需要入侵代码,也就是要修改代码;使用更复杂。

方式一:在命令行中运行

python -m pdb my_script.py

方式二:脚本中运行

在需要设置断点的地方,插入方法 pdb.set_trace()

import ipdb as pdb

s = list()
for i in range(10):
    pdb.set_trace()
    s.append(i)
print(s)

命令: 在进入调试状态之后,就可以输入命令进行调试了。

c: (continue)继续执行
w:(words)显示当前行的上下文信息
a:(arguments)打印当前函数的参数列表
s:(stop)执行当前行,并在顶一个可能的时机停止
n:(next)继续执行直到当前函数的下一行或者函数返回值

通过h可以看到更多的命令,根据需要使用就好了

ipdb> h

Documented commands (type help <topic>):
========================================
EOF    commands   enable    ll        pp       s                until 
a      condition  exit      longlist  psource  skip_hidden      up    
alias  cont       h         n         q        skip_predicates  w     
args   context    help      next      quit     source           whatis
b      continue   ignore    p         r        step             where 
break  d          interact  pdef      restart  tbreak         
bt     debug      j         pdoc      return   u              
c      disable    jump      pfile     retval   unalias        
cl     display    l         pinfo     run      undisplay      
clear  down       list      pinfo2    rv       unt            

Miscellaneous help topics:
==========================
exec  pdb

关于pdb的一些常用命令:

常用的调试命令

h(elp),会打印当前版本Pdb可用的命令,如果要查询某个命令,可以输入 h [command],例如:“h l” — 查看list命令 
l(ist),可以列出当前将要运行的代码块 
(Pdb) l

b(reak), 设置断点,例如 “b 77″,就是在当前脚本的77行打上断点,还能输入函数名作为参数,断点就打到具体的函数入口,如果只敲b,会显示现有的全部断点 

condition bpnumber [condition],设置条件断点,下面语句就是对第4个断点加上条件“a==3(Pdb) condition 4 a==3
(Pdb) b
Num Type Disp Enb Where
4 breakpoint keep yes at /home/jchen/regression/regressionLogCMP.py:504
stop only if a==3

cl(ear),如果后面带有参数,就是清除指定的断点;如果不带参数就是清除所有的断点 
(Pdb) cl
Clear all breaks? y

disable/enable,禁用/激活断点 
(Pdb) disable 3
(Pdb) b
Num Type Disp Enb Where
3 breakpoint keep no at /home/jchen/regression/regressionLogCMP.py:505

n(ext),让程序运行下一行,如果当前语句有一个函数调用,用n是不会进入被调用的函数体中的 

s(tep),跟n相似,但是如果当前有一个函数调用,那么s会进入被调用的函数体中 
c(ont(inue)),让程序正常运行,直到遇到断点 
j(ump),让程序跳转到指定的行数 
(Pdb) j 497

> /home/jchen/regression/regressionLogCMP.py(497)compareLog()
> -> pdb.set_trace()

a(rgs),打印当前函数的参数 
(Pdb) a
_logger =
_base = ./base/MRM-8137.log
_new = ./new/MRM-8137.log
_caseid = 5550001
_toStepNum = 10
_cmpMap = {‘_bcmpbinarylog’:True, ‘_bcmpLog’:True, ‘_bcmpresp’:True}

p,最有用的命令之一,打印某个变量 
(Pdb) p _new
u’./new/MRM-8137.log’

!,感叹号后面跟着语句,可以直接改变某个变量 
q(uit),退出调试 
发现在命令行下调试程序也是一件挺有意思的事情,记录下来分享一下

w ,Print a stack trace, with the most recent frame at the bottom.An arrow indicates the "current frame",
which determines the context of most commands. 'bt' is an alias for this command.

d ,Move the current frame one level down in the stack trace
(to a newer frame).

u ,Move the current frame one level up in the stack trace
(to an older frame).

使用 u 和 d 命令,我们可以在栈帧之间切换,用以获取其相关上下文变量信息。w可以显示最近的一些栈帧信息。

常用的 pdb debug 命令:

命令       用途

  • break 或 b     设置断点
  • continue 或 c   继续执行程序, 或是跳到下个断点
  • list 或 l      查看当前行的代码段
  • step 或 s     进入函数
  • return 或 r     执行代码直到从当前函数返回
  • exit 或 q      中止并退出
  • next 或 n     执行下一行
  • p 或!       打印变量的值,例如p a
  • help 或 h     帮助

其他

pdb调试命令
完整命令   简写命令     描述

  • args a 打印当前函数的参数
  • break      b        设置断点
  • clear cl 清除断点
  • condition 无 设置条件断点
  • continue c或者cont    继续运行,知道遇到断点或者脚本结束
  • disable    无    禁用断点
  • enable    无   启用断点
  • help h 查看pdb帮助
  • ignore     无 忽略断点
  • jump j 跳转到指定行数运行
  • list l 列出脚本清单
  • next n 执行下条语句,遇到函数不进入其内部
  • p    p 打印变量值,也可以用print
  • quit q 退出 pdb
  • return     r 一直运行到函数返回
  • tbreak     无 设置临时断点,断点只中断一次
  • step s 执行下一条语句,遇到函数进入其内部
  • where     w 查看所在的位置
  • !  无 在pdb中执行语句