Python Debug工具
最近在github上冒出了一个python的debug神器PySnooper,号称在debug时可以消灭print。那么该工具有哪些优点呢,如何使用该工具呢。本文就介绍该工具的优缺点和使用方式。
前言
使用python开发过程中,总是避免不了debug。传统的debug过程大致分为两种:
a)断点+单步调试。
断点+单步调试估计是用的最多的了,对于较大型项目来说,其流程大致为:先在关键的代码位置加上print语句,通过分析print的值将范围缩小,这个过程可能需要重复多次,使用print的方法,一般可以将范围缩小到一个比较完整的功能模块中;然后在可能出现bug的模块中的关键部分打上断点,进入到断点后使用单步调试,查看各变量的值是否正确,最后根据错误的变量值定位到具体的代码行,最后进行修改。
b) pdb调试。
pdb是python自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点、单步调试、进入函数调试、查看当前代码、查看栈片段、动态改变变量的值等。pdb的调试流程和1)基本差不多,其具体的使用方法大家可以网上搜一下。
传统的debug的方法的缺点包括:
a)需要在代码中添加print语句,这就改变了原有的代码;
b)在断点调试和单步调试过程中,需要保持持续的专注,一旦跳过了关键点就要从头开始。
最近在github上冒出了一个debug工具,可以解决传统debug过程中的缺点。下面一块来看看这个工具的使用和神奇之处。
Python学习交流群:835017344,这里是python学习者聚集地,有大牛答疑,有资源共享!有想学习python编程的,或是转行,或是大学生,还有工作中想提升自己能力的,正在学习的小伙伴欢迎加入学习。
1. PySnooper是什么
该工具使用采用装饰器的形式,将函数的运行过程以日志的形式打印到文件中,其记录了运行了哪些代码行,运行的时间及运行到当前代码时各变量的值。根据变量的变化就可以定位问题了。亲自试用该工具后,其优点可总结为以下几点:
1、无需为了查看变量的值,使用print打印变量的值,从而修改了原有的代码。
2、接口的运行过程以日志的形式保存,方便随时查看。
3、可以根据需要,设置函数调用的函数的层数,方便将注意力集中在需要重点关注的代码段。
4、多个函数的日志,可以设置日志前缀表示进行标识,方便查看时过滤。
该工具有这么多优点,那么如何使用呢,下面结合demo来介绍该工具的使用。
2. 使用方式介绍
2.1 工具安装
pip install pysnooper
2.2官方demo介绍
官方demo代码:
import pysnooper
@pysnooper.snoop()
def number_to_bits(number):
if number:
bits = []
while number:
number, remainder = divmod(number, 2)
bits.insert(0, remainder)
return bits
else:
return [0]
number_to_bits(6)
控制台输出:
控制台的输出如上图,从图中可以看到,从进入到函数开始,会记录每一行代码的执行及记录新增局部变量或已有局部变量的变化,直到函数结束。以装饰器的形式使用该工具后,会将函数运行的中间结果打印出来,这样方便后续的bug定位和分析。
2.3 参数介绍
以装饰器的形式使用该工具,其包含了四个参数,参数包括output, variables, depth, prefix,如下图。
1、output参数。该参数指定函数运行过程中产生的中间结果的保存位置,若该值为空,则将中间结果输出到控制台。
2、variables参数。该参数是vector类型, 因为在默认情况下,装饰器只跟踪局部变量,要跟踪非局部变量,则可以通过该字段来指定。默认值为空vector。
3、depth参数。该参数表示需要追踪的函数调用的深度。在很多时候,我们在函数中会调用其他函数,通过该参数就可以指定跟踪调用函数的深度。默认值为1。
4、prefix参数。该参数用于指定该函数接口的中间结果前缀。当多个函数都使用的该装饰器后,会将这些函数调用的中间结果保存到一个文件中,此时就可以通过前缀过滤不同函数调用的中间结果。默认值为空字符串。
3. 工具应用
要使用该工具只需要理解该装饰器(snoop)的参数的含义,下面结合几个demo介绍参数的使用及对结果的影响。
3.1 output 参数使用
若使用默认参数,则将中间结果输出到控制台,若填写该参数,则将中间结果写入到该参数指定的目录下,如运行以下代码,其中间结果会保存在装饰器snoop中设置日志保存的路径中,注意这里不会自动创建目录,所以需要事先创建目录,如测试代码中填写路径后需要创建log目录。
测试代码:
import pysnooper
def add(num1, num2):
return num1 + num2
@pysnooper.snoop("./log/debug.log", prefix="--*--")
def multiplication(num1, num2):
sum_value = 0
for i in range(0, num1):
sum_value = add(sum_value, num2)
return sum_value
value = multiplication(3, 4)
运行该代码后,在./log/debug.log的内容如下:
从运行代码的中间结果中可以看出,文件中记录了各行代码的执行过程及局部变量的变化。在debug时,通过分析该文件,就可以跟踪每一步的执行过程及局部变量的变化,这样就能快速的定位问题所在;由于运行的中间结果保存在文件中,方便随时分析其运行的中间结果,也便于共享。
3.2 variables参数使用
在默认参数的情况下,使用该工具只能查看局变量的变化过程,当需要查看局部变量以外变量时,则可以通过variables参数进行设置,比如下方代码,在Foo类型,需要查看类实例的变量self.num1, self.num2, self.sum_value,则可以看将该变量设置当参数传入snoop的装饰器中。
测试代码:
import pysnooper
class Foo(object):
def __init__(self):
self.num1 = 0
self.num2 = 0
self.sum_value = 0
def add(self, num1, num2):
return num1 + num2
@pysnooper.snoop(output="./log/debug.log", variables=("self.num1", "self.num2", "self.sum_value"))
def multiplication(self, num1, num2):
self.num1 = num1
self.num2 = num2
sum_value = 0
for i in range(0, num1):
sum_value = self.add(sum_value, num2)
self.sum_value = sum_value
return sum_value
foo = Foo()
foo.multiplication(3, 4)
为了体现该参数的作用,这里分别使用默认参数和上述参数(代码中设置的参数)运行代码,得到的结果如下:
从两个中间结果中可以看出,若变量不是局部变量,哪怕在函数中使用了该变量,如果不显示设置打印该变量的中间结果,则不会将该变量的中间结果打印到文件中。
3.3 depth参数使用
该参数用来指定记录函数调用层数的结果,默认值为1,若要查看多层函数调用的中间结果,则可将该参数设置为>=2。
测试代码:
import pysnooper
def add(num1, num2):
return num1 + num2
@pysnooper.snoop("./log/debug.log", depth=2)
def multiplication(num1, num2):
sum_value = 0
for i in range(0, num1):
sum_value = add(sum_value, num2)
return sum_value
value = multiplication(3, 4)
为了对比,将depth的值分别设置为1和2,其结果如下:
从上述结果中可以看出,若要查看更深层次函数调用的情况,则可以通过设置depth值进行查看。这样方便用户有选择性的查看函数的调用情况。
3.4 prefix参数使用
该参数主要用于设置中间结果的前缀,这样就可以区分不同的函数调用的中间结果,默认参数为""。
测试代码:
import pysnooper
def add(num1, num2):
return num1 + num2
@pysnooper.snoop("./log/debug.log", prefix="--*--")
def multiplication(num1, num2):
sum_value = 0
for i in range(0, num1):
sum_value = add(sum_value, num2)
return sum_value
value = multiplication(3, 4)
运行代码后的中间结果如下:
从结果中可以看到,中间结果的每一行都包含了prefix设置的前缀,这样便于区分不同的函数调用的中间结果。
上述的介绍为了将注意力集中到具体的参数,采取设置单一参数的形式进行介绍(output+其他单个参数)。在实际使用时,可以同时设置多个参数。使用PySnooper工具来记录函数运行的中间结果,比起传统的使用断点+单步调试,pdb等调试方法,PySnooper工具有着巨大的优势。
4. 该工具的不足之处
虽然使用debug在使用PySnooper很方便,但还是存在一些问题(以4月26号拉取代码为依据),比如:
1、无法很好的支持递归调用。
2、调用每个函数的中间结果只能保存在一个文件中,如果需要区分不同文件的结果,需要使用prefix来进行前缀标识。
3、对于跨文件函数调用,不支持记录调用函数所在的文件名。
当然PySnooper是最近在github上火起来的项目,还不够完善是正常的,相信这些不足之处后续也会得到完善,期待一个更好的PySnooper。
5. 总结
本文介绍PpySnooper的工具,先介绍了该工具是什么,相比传统debug方法的优势,然后介绍了该工具的参数及说明该参数作用的demo。最后介绍了该工具的不足之处。
https://www.jianshu.com/p/e5d84304d232
Python Debug工具的更多相关文章
- 极简Python DeBug工具——PySnooper
DeBug Python 代码的方式有很多种?比如: (1)设置断点 (2)print函数 (3)... 本文要介绍的是一个新开源的项目PySnooper ,只要给有疑问的代码加上装饰器,各种信息一目 ...
- 【Machine Learning】Python开发工具:Anaconda+Sublime
Python开发工具:Anaconda+Sublime 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现 ...
- Python 开发工具推荐
对于开发工具,仁者见仁智者见智,关键是自己喜欢,用着顺手就好,不用刻意去追求别人用的是什么工具. 这里给大家主要推荐三款工具,分别是PyCharm.Sublime Text 3.VS Code,因为这 ...
- Python开发工具PyCharm个性化设置(图解)
Python开发工具PyCharm个性化设置,包括设置默认PyCharm解析器.设置缩进符为制表符.设置IDE皮肤主题等,大家参考使用吧. JetBrains PyCharm Pro 4.5.3 中文 ...
- Yii2的Debug工具
yii2的Debug工具 调用 r=debug 可以对程序进行性能分析,从而对程序进行改良 (1)数据库某条sql语句的执行时间 (2)debug的profiling标签 \YII::beginP ...
- yii2 debug工具条不出现
UrlManger美化后,debug工具条不出现,禁用UrlManager出现
- 下破解安装Python开发工具WingIDE4.1
步骤: 1.将系统时间调整到一个月之前,然后执行安装. 可以使用date命令调整系统时间,如:date -s '2012-08-14 10:00:00' 2.安装成功后,打开程序,按照提示信息,申请一 ...
- Python小工具--删除svn文件
有的时候我们需要删除项目下的svn相关文件,但是SVN会在所有的目录下都创建隐藏文件.svn,手工一个个目录查找然后删除显然比较麻烦.所以这里提供了一个Python小工具用于批量删除svn的相关文件: ...
- arcgis通过 Python 使用工具 获得结果信息
通过 Python 使用工具 ArcGIS 10 每个地理处理工具都具有一组固定的参数,这些参数为工具提供执行所需的信息.工具通常具有定义一个或多个数据集的输入参数,这些数据集一般用于生成新的输出数据 ...
随机推荐
- Flink问题1
flink问题1 报错: More buffers requested available than totally available 查看源码: /** * This method makes s ...
- [C#] (原创)一步一步教你自定义控件——05,Label(原生控件)
一.前言 技术没有先进与落后,只有合适与不合适. 自定义控件可以分为三类: 一类是"无中生有".就如之前文章中的的那些控件,都是继承基类Control,来实现特定的功能效果: 一类 ...
- MySQL 触发器、存储过程 练习
创建表并插入数据: ``` 字段名 数据类型 主键 外键 非空 唯一 自增 id INT 是 否 是 是 否 name VARCHAR(50) 否 否 ...
- jdbc编程学习(1)
一,背景 1996年,sun公司发布了第一版本的数据库连接(JDBC)API,使编程人员可以通过这个API接口连接到数据库,并使用结构化查询语言(SQL)完成对数据库的查找与更新.JDBC自此成为Ja ...
- ArrayList之SubList源码解析
subList是ArrayList的内部类, public List<E> subList(int fromIndex, int toIndex) { subListRangeCheck( ...
- linux yum install
作为一名新手,学习Linux已经一个月了,其间遇到了不少问题,而今天笔者遇到的问题是 #yum install pam-devel #This system is not registered to ...
- 【Mongodb】后台主键_id自增(Java版本)
ObjectId的选择 创建MongoDB文档时,如果没有赋值ID,系统会自动帮你创建一个,通常会在客户端由驱动程序完成.得到的ObjectId类似于这种 ObjectId使用12字节的存储空间, ...
- 使用swagger上传文件
经常使用swagger,可以通过设置[ProducesResponseType]标记接口的返回信息:swagger也能通过接口的参数列表,自动获得发送的数据结构信息. 不过有一个例外,就是上传文件的时 ...
- [leetcode]Next Greater Element
第一题:寻找子集合中每个元素在原集合中右边第一个比它大的数. 想到了用哈希表存这个数的位置,但是没有想到可以直接用哈希表存next great,用栈存还没找到的数,没遍历一个数就考察栈中的元素小,小的 ...
- Spring Data JPA简介 Spring Data JPA特点
Spring Data JPA 是Spring基于ORM框架.JPA规范的基础上封装的一套JPA 应用框架,底层使用了Hibernate 的JPA技术实现,可使开发者用极简的代码即可实现对数据的访问和 ...