给大家推荐本我自己写的电子书《PyCharm中文指南》,把各种 PyCharm 的高效的使用技巧用GIF动态图的形式展示出来。有兴趣的可以看它的在线文档:

http://pycharm.iswbm.com

对于每个程序开发者来说,调试几乎是必备技能。

代码写到一半卡住了,不知道这个函数执行完的返回结果是怎样的?调试一下看看

代码运行到一半报错了,什么情况?怎么跟预期的不一样?调试一下看看

调试的方法多种多样,不同的调试方法适合不同的场景和人群。

如果你是刚接触编程的小萌新,对很多工具的使用还不是很熟练,那么 print 和 log 大法好

如果你在本地(Win或者Mac)电脑上开发,那么 IDE 的图形化界面调试无疑是最适合的;

如果你在服务器上排查BUG,那么使用 PDB 进行无图形界面的调试应该是首选;

如果你要在本地进行开发,但是项目的进行需要依赖复杂的服务器环境,那么可以了解下 PyCharm 的远程调试

除了以上,今天明哥再给你介绍一款非常好用的调试工具,它能在一些场景下,大幅度提高调试的效率, 那就是 PySnooper,它在 Github 上已经收到了 13k 的 star,获得大家的一致好评。

有了这个工具后,就算是小萌新也可以直接无门槛上手,从此与 print 说再见~

1. 快速安装

执行下面这些命令进行安装 PySnooper

$ python3 -m pip install pysnooper

# 或者

$ conda install -c conda-forge pysnooper

# 或者

$ yay -S python-pysnooper

2. 简单案例

下面这段代码,定义了一个 demo_func 的函数,在里面生成一个 profile 的字典变量,然后去更新它,最后返回。

代码本身没有什么实际意义,但是用来演示 PySnooper 已经足够。

import pysnooper

@pysnooper.snoop()

def demo_func():

profile = {}

profile["name"] = "写代码的明哥"

profile["age"] = 27

profile["gender"] = "male"

return profile

def main():

profile = demo_func()

main()

现在我使用终端命令行的方式来运行它

[root@iswbm ~]# python3 demo.py

Source path:... demo.py

17:52:49.624943 call 4 def demo_func():

17:52:49.625124 line 5 profile = {}

New var:....... profile = {}

17:52:49.625156 line 6 profile["name"] = "写代码的明哥"

Modified var:.. profile = {'name': '写代码的明哥'}

17:52:49.625207 line 7 profile["age"] = 27

Modified var:.. profile = {'name': '写代码的明哥', 'age': 27}

17:52:49.625254 line 8 profile["gender"] = "male"

Modified var:.. profile = {'name': '写代码的明哥', 'age': 27, 'gender': 'male'}

17:52:49.625306 line 10 return profile

17:52:49.625344 return 10 return profile

Return value:.. {'name': '写代码的明哥', 'age': 27, 'gender': 'male'}

Elapsed time: 00:00:00.000486

可以看到 PySnooper 把函数运行的过程全部记录了下来,包括:

代码的片段、行号等信息,以及每一行代码是何时调用的?

函数内局部变量的值如何变化的?何时新增了变量,何时修改了变量。

函数的返回值是什么?

运行函数消耗了多少时间?

而作为开发者,要得到这些如此详细的调试信息,你需要做的非常简单,只要给你想要调试的函数上带上一顶帽子(装饰器) -- @pysnooper.snoop() 即可。

3. 详细使用

2.1 重定向到日志文件

@pysnooper.snoop() 不加任何参数时,会默认将调试的信息输出到标准输出。

对于单次调试就能解决的 BUG ,这样没有什么问题,但是有一些 BUG 只有在特定的场景下才会出现,需要你把程序放在后面跑个一段时间才能复现。

这种情况下,你可以将调试信息重定向输出到某一日志文件中,方便追溯排查。

@pysnooper.snoop(output='/var/log/debug.log')

def demo_func():

...

2.2 跟踪非局部变量值

PySnooper 是以函数为单位进行调试的,它默认只会跟踪函数体内的局部变量,若想跟踪全局变量,可以给 @pysnooper.snoop() 加上 watch 参数

out = {"foo": "bar"}

@pysnooper.snoop(watch=('out["foo"]'))

def demo_func():

...

如此一来,PySnooper 会在 out["foo"] 值有变化时,也将其打印出来

watch 参数,接收一个可迭代对象(可以是list 或者 tuple),里面的元素为字符串表达式,什么意思呢?看下面例子就知道了

@pysnooper.snoop(watch=('out["foo"]', 'foo.bar', 'self.foo["bar"]'))

def demo_func():

...

和 watch 相对的,pysnooper.snoop() 还可以接收一个函数 watch_explode,表示除了这几个参数外的其他所有全局变量都监控。

@pysnooper.snoop(watch_explode=('foo', 'bar'))

def demo_func():

...

2.3 设置跟踪函数的深度

当你使用 PySnooper 调试某个函数时,若该函数中还调用了其他函数,PySnooper 是不会傻傻的跟踪进去的。

如果你想继续跟踪该函数中调用的其他函数,可以通过指定 depth 参数来设置跟踪深度(不指定的话默认为 1)。

@pysnooper.snoop(depth=2)

def demo_func():

...

2.4 设置调试日志的前缀

当你在使用 PySnooper 跟踪多个函数时,调试的日志会显得杂乱无章,不方便查看。

在这种情况下,PySnooper 提供了一个参数,方便你为不同的函数设置不同的标志,方便你在查看日志时进行区分。

@pysnooper.snoop(output="/var/log/debug.log", prefix="demo_func: ")

def demo_func():

...

效果如下

2.5 设置最大的输出长度

默认情况下,PySnooper 输出的变量和异常信息,如果超过 100 个字符,被会截断为 100 个字符。

当然你也可以通过指定参数 进行修改

@pysnooper.snoop(max_variable_length=200)

def demo_func():

...

您也可以使用max_variable_length=None它从不截断它们。

@pysnooper.snoop(max_variable_length=None)

def demo_func():

...

2.6 支持多线程调试模式

PySnooper 同样支持多线程的调试,通过设置参数 thread_info=True,它就会在日志中打印出是在哪个线程对变量进行的修改。

@pysnooper.snoop(thread_info=True)

def demo_func():

...

效果如下

2.7 自定义对象的格式输出

pysnooper.snoop() 函数有一个参数是 custom_repr,它接收一个元组对象。

在这个元组里,你可以指定特定类型的对象以特定格式进行输出。

这边我举个例子。

假如我要跟踪 person 这个 Person 类型的对象,由于它不是常规的 Python 基础类型,PySnooper 是无法正常输出它的信息的。

因此我在 pysnooper.snoop() 函数中设置了 custom_repr 参数,该参数的第一个元素为 Person,第二个元素为 print_persion_obj 函数。

PySnooper 在打印对象的调试信息时,会逐个判断它是否是 Person 类型的对象,若是,就将该对象传入 print_persion_obj 函数中,由该函数来决定如何显示这个对象的信息。

class Person:pass

def print_person_obj(obj):

return f""

@pysnooper.snoop(custom_repr=(Person, print_person_obj))

def demo_func():

...

完整的代码如下

import pysnooper

class Person:pass

def print_person_obj(obj):

return f""

@pysnooper.snoop(custom_repr=(Person, print_person_obj))

def demo_func():

person = Person()

person.name = "写代码的明哥"

person.age = 27

person.gender = "male"

return person

def main():

profile = demo_func()

main()

运行一下,观察一下效果。

如果你要自定义格式输出的有很多个类型,那么 custom_repr 参数的值可以这么写

@pysnooper.snoop(custom_repr=((Person, print_person_obj), (numpy.ndarray, print_ndarray)))

def demo_func():

...

还有一点我提醒一下,元组的第一个元素可以是类型(如类名Person 或者其他基础类型 list等),也可以是一个判断对象类型的函数。

也就是说,下面三种写法是等价的。

# 【第一种写法】

@pysnooper.snoop(custom_repr=(Person, print_persion_obj))

def demo_func():

...

# 【第二种写法】

def is_persion_obj(obj):

return isinstance(obj, Person)

@pysnooper.snoop(custom_repr=(is_persion_obj, print_persion_obj))

def demo_func():

...

# 【第三种写法】

@pysnooper.snoop(custom_repr=(lambda obj: isinstance(obj, Person), print_persion_obj))

def demo_func():

...

以上就是明哥今天给大家介绍的一款调试神器(PySnooper) 的详细使用手册,是不是觉得还不错?

内容来源于网络如有侵权请私信删除

python 如何边改代码边调试_Python 代码调试神器:PySnooper相关推荐

  1. python代码质量检查工具_python代码检查工具pylint 让你的python更规范

    复制代码 代码如下: #coding:utf-8 ''' a test function module ''' import urllib import time def fetch(url): '' ...

  2. python逐行调试_python怎么调试

    python代码执行中,有时我们遇到了错误,但不确定具体是什么位置出现错误,这是我们希望能够进行一步步调试确认,下文教你如何进行调试工作 工具/原料 python 方法1 1 使用python自带工具 ...

  3. python逐行调试_python单步调试

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 本文由腾讯云+社区自动同步,原文地址 https:stackoverflow.c ...

  4. python代码规范工具_Python代码规范Flake8的简单示例

    这篇文章主要为大家详细介绍了Python代码规范Flake8的简单示例,具有一定的参考价值,可以用来参考一下. 对python这个高级语言感兴趣的小伙伴,下面一起跟随512笔记的小编两巴掌来看看吧! ...

  5. python代码重构技巧_Python代码重构

    代码重构是一件很是辛苦却很是有意义的事情,代码重构的缘由在于:django 一.代码过于冗余.沉余架构 二.代码过于耦合函数 三.代码过于复杂学习 四.接口调用超出三层优化 此次重构主要在于架构问题, ...

  6. 用python将xml文件转换为txt文件_python代码xml转txt实例

    为了训练深度学习模型,经常要整理大量的标注数据,需统一不同格式的标注数据,一般情况下习惯读取TXT格式的数据.但实际中经常遇到XML格式的标注数据,在此举例:1.读取XML标注数据:2.写入TXT文件 ...

  7. python下面代码是什么_python代码下面__name__= __main__怎么使用 作用是什么?

    name = '__main__' 的作用 有句话经典的概括了这段代码的意义: "Make a script both importable and executable" 意思就 ...

  8. python代码块缩进_Python代码需要缩进吗

    Python则是通过缩进来识别代码块的. 缩进 Python最具特色的是用缩进来标明成块的代码.我下面以if选择结构来举例.if后面跟随条件,如果条件成立,则执行归属于if的一个代码块. 先看C语言的 ...

  9. python手写数字识别实验报告_Python代码实现简单的MNIST手写数字识别(适合初学者看)...

    补充:由于很多同学找我要原数据集和代码,所以我上传到了资源里,https://download..net/download/zugexiaodui/10913834 初学机器学习,第一步是做一个简单的 ...

最新文章

  1. centos lustre 简单 安装教程
  2. 033_使用ArrayDeque模拟队列结构
  3. Interview:算法岗位面试—10.11下午—上海某公司算法岗位(偏数据分析,证券金融行业)技术面试考点之sqlserver语言相关考察点复习
  4. c语言建立线性表(顺序储存,链式储存,循环,双向)全
  5. c语言向自定数组_C语言一维数组的定义和引用
  6. IS2009制作Oracle 静默安装包(二) 感谢空白先生特许授权
  7. 使用MVCPager做AJAX分页所需要注意的地方
  8. 计算机专业导论论文2000字,计算机专业导论论文.doc
  9. 对数字信号处理中各种频率以及分辨率的理解
  10. 鸿蒙系统硬盘分区,硬盘分区2种格式
  11. QQ音乐下载器、爬虫
  12. java中的创建和调用_如何在Mirth Connect中创建和调用自定义Java代码
  13. Python爬取必应图片2
  14. winxp找不到服务器或 dns 错误,详解网络无法使用DNS错误的修复步骤
  15. 【时间序列】时间序列曲线平滑+预测(LSTM)
  16. DOTA2匹配机制详解
  17. 创新突破,索爱S5耳机实现空间音频和动态头部跟踪
  18. 第七章 马斯洛金字塔模型
  19. 多重纹理——像素着色器
  20. 果快服务器维护中 稍后再试,维护中什么意思?服务维护中是什么意思

热门文章

  1. getter方法的作用 vuex_Vuex的工作流程
  2. 传统手工特征--opencv
  3. tcp四次挥手,为什么是四次?
  4. python 模块 chardet下载方法及介绍
  5. Extract Subclass(提炼子类)
  6. html盒子嵌套居中,css在盒子中垂直居中和固定居中
  7. oracle exec编译失效,编译oracle失效的函数、存储过程、视图等
  8. leetcode No.2 两数相加
  9. 记录---基于BigDecimal的特殊的四舍五入
  10. java 时间的相关转换操作