调试是开发过程中不可避免的一个环节,在Python中我们使用print、logging、assert等方法进行调试既简单又实用,但毕竟有其局限性。今天这篇文章为大家带来三个工具,其中有Python的内置模块也有第三方库,它们提供了调试代码所需的大部分常用功能,将极大的提升我们的开发和bug排除效率。

1.PDB

pdb是Python中的一个内置模块,启用pdb后可以对代码进行断点设置和跟踪调试。为了演示方便,我们准备一个样例程序pdb_test.py:

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指令,调试效果如下:

这时我们就可以通过各种命令控制代码执行或者查看当前变量,例如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)

pdb.set_trace()的作用就是在代码中设置断点,在pdb调试模式下,使用c命令就会直接跳转到下一个断点位置,如果之后没有其他断点就会执行完全部代码,调试效果如下:

除了上面提到的几个指令以外,pdb还有其他一些比较常用的命令(见下表),综合使用基本能够满足日常的调试需求。

2.Better-exceptions

better-exceptions是一个Python第三方库,作者对他的定义是“使异常信息更加美观和详尽”。在正式使用之前先说下这个库的安装:

第一步,使用pip install better_exceptions安装better-exceptions库;

第二步,使用export BETTER_EXCEPTIONS=1(Linux / OSX)或setx BETTER_EXCEPTIONS 1(Windows)设置环境变量。

现在就可以正常使用better-exceptions进行调试了,为了演示效果更加明显,我们对上文中的代码稍作修改作为本次的样例程序better_test.py:

def divisionnumber(number, div):

for i in range(div):

print(number / i)

if __name__ == '__main__':

divisionnumber(10, 10)

很明显,上面这段代码在执行过程中会因为分母为0而抛出异常,现在我们执行python better_test.py,看看启用了better-exceptions后的异常信息是什么样子的:

从上面这幅图可以看出better-exceptions对异常信息的修改主要体现在两个方面:

一是对产生异常的代码进行了颜色标注;

二是对产生异常的代码中的相关变量值进行了输出(包括函数等对象);

这样一来,很多时候我们只需要根据better-exceptions输出的辅助信息就能判断产生异常的位置和原因,而不必像以前一样再次查看源代码并观察运行结果,正如作者所说:Pretty and more helpful。

但是,过多的信息输出也会有问题,那就是当代码层级结构比较复杂的时候,better-exceptions输出的辅助信息可能会非常之多,就比如上面的divisionnumber函数,他所在的地址信息多数时候我们并不关心,为了屏蔽这些“垃圾”信息,我们可以在代码中加一行:

better_exceptions.MAX_LENGTH = XXX

XXX是允许显示的最大字符长度,比如这里设置为10,再来运行better_test.py这个程序就会是下面的结果:

可以看到,对函数divisionnumber的注释只显示了最开始的"

除了上面提到的功能之外,better-exceptions还可以和logging还有django无缝接入,这使得它的应用更加灵活,关于这方面内容大家可以查看项目文档。

还有一点需要提醒大家,如果你是在windows下使用,可能会出现下图中的乱码问题,这是由于better-exceptions的内设编码格式所导致的。

解决的办法是在安装后,对better_exceptions目录下的encoding.py文件第10行代码进行如下修改:

# 原代码:

ENCODING = locale.getpreferredencoding()

# 修改为:

ENCODING = 'utf-8'

3.PySnooper

PySnooper也是一个Python的第三方库,他的特点是能够精准的显示每条代码的执行顺序、执行时间以及随之带来的局部变量的改变等等。值得一提的是,作为一个发布不满半年的库,PySnooper在github上已经达到了1.2W星,其受欢迎程度可见一斑。

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()

在上面这段代码中,我们先是生成10个1到1000之间的随机数,然后计算他们之中的最大最小值和中位数,唯一的不同在于第三行多了一条语句@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跟踪监控的结果,正如上面所说,他准确记录的每条代码的运行时间、顺序以及相关的变量值。

作为一个星标1.2W+的项目,PySnooper的功能肯定不会这么简单,@pysnooper.snoop()中是可以接收参数的,比如我们觉得输出内容太多,可以考虑把信息记录到log日志中,这个功能只需要加一个log文件定位参数就能搞定:

@pysnooper.snoop('file.log')

@pysnooper.snoop()支持的参数还有很多,分别对应了不同的功能,例如监控自定义表达式、监控底层函数、支持多线程等等,详见项目文档。

此外,pysnooper还支持局部监控,一般来说我们写的代码都比较长,而需要监控的只是其中的一小部分,这时候就可以把需要监控的代码放到一个block里。我们修改下刚才的代码,只对计算最大最小值和中位数的部分进行监控,修改后的代码如下:

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()模式依然保留了对各种参数的支持,个人认为这种模式更加符合实践需求。

小结:

今天介绍了三个不借助IDE就能方便使用的调试工具,三个工具的调试思路和适用场景也各不相同,大家可以根据需要灵活选用。不过话说回来,我个人最喜欢的还是PySnooper,你最喜欢哪一款呢?

python调试神器_Python里三个最高逼格的调试神器相关推荐

  1. qdebug 调试 输出乱码_Python里三个最高逼格的调试神器

    调试是开发过程中不可避免的一个环节,在Python中我们使用print.logging.assert等方法进行调试既简单又实用,但毕竟有其局限性.今天这篇文章为大家带来三个工具,其中有Python的内 ...

  2. Python里三个最高逼格的调试神器

    调试是开发过程中不可避免的一个环节,在Python中我们使用print.logging.assert等方法进行调试既简单又实用,但毕竟有其局限性.今天这篇文章为大家带来三个工具,其中有Python的内 ...

  3. python好用-Python里三个好用的调试神器

    1.PDB pdb是Python中的一个内置模块,启用pdb后可以对代码进行断点设置和跟踪调试.为了演示方便,我们准备一个样例程序pdb_test.py: def countnumber(number ...

  4. python调试教程_python进阶教程之==、is和调试

    ==.is 总结 is 是比较两个引用是否指向了同一个对象(引用比较).== 是比较两个对象是否相等. 调试 pdb pdb是基于命令行的调试工具,非常类似gnu的gdb(调试c/c++). 命令简写 ...

  5. python可爱代码_Python里那些可爱的游戏模块们

    一晃自己用python写小游戏也有段时间了,自娱自乐之余,也对这些模块如数家珍下,仅做一家之言供后来者参考吧. 首先是范畴问题,python适合写什么游戏呢? 简言之,python适合写一些2D的小游 ...

  6. python 格式化字符串_Python字符串三种格式化输出

    字符串格式化输出是python非常重要的基础语法,今天就把三种格式化输出做一个简单的总结,希望对大家有帮助. 格式化输出:内容按照一定格式要求进行输出. 1.使用占位符%输出 python2.6版本之 ...

  7. python list排序_python里对list中的整数求平均并排序

    python里对list中的整数求平均并排序 本文主要记述了使用Python将list重点整数求平均值之后在进行排列的过程,并把代码分享给大家, 问题 定义一个int型的一维数组,包含40个元素,用来 ...

  8. python纵向数据分析_python数据分析三个重要方法之:numpy和pandas

    关于数据分析的组件之一:numpy ndarray的属性 4个必记参数: ndim:维度 shape:形状(各维度的长度) size:总长度 dtype:元素类型 一:np.array()产生n维数组 ...

  9. cmdb python 采集虚拟机_Python编程(三十四):CMDB后台管理、封装自定义JS组件、前端td标签定制显示内容及属性...

    一. CMDB后台管理 CMDB管理主要分为采集资产.API接口.后台管理.这里主要介绍CMDB后台管理. - 采集资产 - API - 后台管理- 资产列表- 业务线列表- 用户列表- 组列表... ...

最新文章

  1. svd奇异值分解_SVD(奇异值分解)到底在干什么
  2. 【leetcode】258. Add Digits
  3. 如何给DataFrame的列命名或重命名。
  4. 从文件中读取数据,排序之后输出到另一个文件中
  5. 完全开源im框架_【行业资讯】移动端开源 IM 框架 MobileIMSDK v5.0 发布!
  6. 指静脉识别技术在安防行业的应用前景
  7. Shiro系列-Shiro简介
  8. nginx 1.11.0实现http和https正向代理
  9. AOP拦截+权限验证+返回默认接口对象
  10. 连接池简介及其工作原理
  11. Lotus Symphony 正式版发布!
  12. 梦回山海推广码jn0010 梦回山海推广码
  13. 合肥工业大学C语言提交作业,合肥工业大学C语言题库程序设计.doc
  14. Sonatype Nexus Maven仓库搭建和管理
  15. 数字时代的中国支付体系现代化——DC/EP与数字人民币
  16. 如何让div透明,内容不透明
  17. 区块链架构与交易流程(fabric1.0)
  18. 保护你系统安全的影子系统
  19. Oracle IMP-00003: 遇到 ORACLE 错误 20001,导数据出现问题
  20. 为canvas添加背景图片

热门文章

  1. JavaScript学习笔记 -- ES6学习(三) 变量的解构赋值
  2. iOS开发拓展篇—音频处理(音乐播放器3)
  3. ISO七层参考模型, TCP/IP
  4. PHP - 验证用户名
  5. Oracle v$session_longops 视图说明
  6. 导入新项目报错 Hibernate提示:No generator named ID_GENERATOR is defined in the persistence unit
  7. 2017计算机基础教学大纲,2017级大学计算机基础教学大纲
  8. mysql日志备份的脚本_脚本备份MySQL数据库和binlog日志
  9. 在Windows下安装和配置Node.js环境v8.11.3与遇到的问题
  10. tomcat端口被占用了怎么办