调试是开发过程中不可避免的一个环节,在Python中我们使用print、logging、assert等方法进行调试既简单又实用,但毕竟有其局限性。今天这篇文章为大家带来三个工具,其中有Python的内置模块也有第三方库,它们提供了调试代码所需的大部分常用功能,将极大的提升我们的开发和bug排除效率。
1.PDB
def countnumber(number):
for i in range(number):
print(i)
if __name__ == '__main__':
countnumber(10)
之后在终端中输入python -m pdb pdb_test.py
命令,进入pdb的调试模式:
l
可以查看所有代码,n
是执行下一步代码,p
可以查看当前变量等等,需要注意的是命令n
只会执行主程序中的代码,如果想要单步执行子函数中的代码,需要使用s
指令,调试效果如下:
s
指令(如果只想在主函数中单步执行可以使用n
)和p
指令,我们控制程序单步运行并实时查看了相关变量。但是单步执行毕竟是一种效率非常低下的调试方式,尤其当代码量比较大的时候更是噩梦,这时就需要用到pdb的set_trace()方法,我们对样例程序pdb_test.py做一点修改:
import pdb
def countnumber(number):
for i in range(number):
print(i)
pdb.set_trace()
if __name__ == '__main__':
countnumber(10)
c
命令就会直接跳转到下一个断点位置,如果之后没有其他断点就会执行完全部代码,调试效果如下:
2.Better-exceptions
pip install better_exceptions
安装better-exceptions库;
export BETTER_EXCEPTIONS=1
(Linux / OSX)或setx BETTER_EXCEPTIONS 1
(Windows)设置环境变量。
def divisionnumber(number, div):
for i in range(div):
print(number / i)
if __name__ == '__main__':
divisionnumber(10, 10)
python better_test.py
,看看启用了better-exceptions后的异常信息是什么样子的:
从上面这幅图可以看出better-exceptions对异常信息的修改主要体现在两个方面:
一是对产生异常的代码进行了颜色标注;
二是对产生异常的代码中的相关变量值进行了输出(包括函数等对象);
better_exceptions.MAX_LENGTH = XXX
# 原代码:
ENCODING = locale.getpreferredencoding()
# 修改为:
ENCODING = 'utf-8'
3.PySnooper
pip install pysnooper
或者conda install -c conda-forge pysnooper
安装这个库。我们还是举一个例子来进行演示,样例代码如下:
import pysnooper
import random
@pysnooper.snoop()
def foo():
lst = []
for i in range(10):
lst.append(random.randrange(1, 1000))
lower = min(lst)
upper = max(lst)
mid = (lower + upper) / 2
print(lower, mid, upper)
foo()
@pysnooper.snoop()
,我们运行以下代码,发现除了正常的print结果之外,多了许多内容(内容太多,下面只显示一部分):
19:51:57.704857 call 16 def foo():
19:51:57.705860 line 17 lst = []
New var:....... lst = []
19:51:57.705860 line 18 for i in range(10):
New var:....... i = 0
19:51:57.705860 line 19 lst.append(random.randrange(1, 1000))
Modified var:.. lst = [758]
19:51:57.705860 line 18 for i in range(10):
Modified var:.. i = 1
....................
19:51:57.706818 line 22 upper = max(lst)
New var:....... upper = 927
19:51:57.706818 line 23 mid = (lower + upper) / 2
New var:....... mid = 552.0
19:51:57.706818 line 24 print(lower, mid, upper)
19:51:57.706818 return 24 print(lower, mid, upper)
Return value:.. None
@pysnooper.snoop()
中是可以接收参数的,比如我们觉得输出内容太多,可以考虑把信息记录到log日志中,这个功能只需要加一个log文件定位参数就能搞定:
@pysnooper.snoop('file.log')
@pysnooper.snoop()
支持的参数还有很多,分别对应了不同的功能,例如监控自定义表达式、监控底层函数、支持多线程等等,详见项目文档。
import pysnooper
import random
def foo():
lst = []
for i in range(10):
lst.append(random.randrange(1, 1000))
with pysnooper.snoop():
lower = min(lst)
upper = max(lst)
mid = (lower + upper) / 2
print(lower, mid, upper)
foo()
运行之后发现监控信息精简了很多:
New var:....... lst = [562, 341, 552, 353, 628, 302, 430, 188, 955, 108]
New var:....... i = 9
20:02:47.359272 line 21 lower = min(lst)
New var:....... lower = 108
20:02:47.359272 line 22 upper = max(lst)
New var:....... upper = 955
20:02:47.360269 line 23 mid = (lower + upper) / 2
with pysnooper.snoop()
模式依然保留了对各种参数的支持,个人认为这种模式更加符合实践需求。
零基础必读热门: