通过PySnooper调试python代码

PySnooper是一款适合菜鸟用的代码调试工具。 如果Python代码哪儿输出不对劲了,之前一般都是利用print函数结合pdb.setTrace()来找问题,如果使用pysnooper的话,那事情就变得简单了!

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. 详细使用

3.1 重定向到日志文件

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

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

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

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

3.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():  
   ...

3.3 设置跟踪函数的深度

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

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

@pysnooper.snoop(depth=2)  
def demo_func():  
...

3.4 设置调试日志的前缀

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

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

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

效果如下

3.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():  
   ...

3.6 支持多线程调试模式

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

@pysnooper.snoop(thread_info=True)  
def demo_func():  
   ...

效果如下

3.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():  
   ...

原创文章,作者:晴川运维,如若转载,请注明出处:https://baike.qcidc.com/4448.html

(0)
晴川运维晴川运维
上一篇 2025年6月8日
下一篇 2025年6月8日

相关推荐

  • 快速上手Zabbix使用方法

    Zabbix是一款能够监控各种网络参数以及服务器健康性和完整性的软件。Zabbix使用灵活的通知机制,允许用户为几乎任何事件配置基于邮件的告警。这样可以快速反馈服务器的问题。基于已…

    Linux系统 2025年6月18日
  • C++中常量与指针讲解

    在C++学习使用过程中,每个人都不可避免地使用指针,而且都或多或少的接触过常量指针或指针常量,但是对这两个的概念还是很容易搞糊涂的,所以这篇文章主要给大家介绍了关于C++中常量与指…

    Linux系统 2025年10月19日
  • Mongodb复制集的安装和部署

    Mongodb复制集由一组Mongod实例(进程)组成,包含一个Primary节点和多个Secondary节点,Mongodb Driver(客户端)的所有数据都写入Primary…

    Linux系统 2025年6月22日
  • 对Linux终端和Shell提示符进行美化

    本篇文章重点为大家讲解一下对Linux终端和Shell提示符进行美化具体方法,有需要的小伙伴可以参考一下。 在Bash中,可以添加表情符号、更改颜色、添加字体样式,以及在每次绘制提…

    Linux系统 2025年10月23日
  • Linux中高效的学习数学

    Linux 提供了大量的教育软件和许多优秀的工具来帮助各种年龄段和年级的学生学习和练习各种各样的习题,这通常是以交互的方式进行。本文为这些各种各样的教育软件和应用提供了一个介绍。 …

    Linux系统 2025年6月4日
  • 简单介绍一下HTTP X-Forwarded-For

    X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HT…

    Linux系统 2025年6月30日
  • 详解Linux下cpustat的安装和使用方法

    cpustat 是 Linux下用Go编写的系统性能测量程序,它通过使用 “用于分析任意系统的性能的方法(USE)”,以有效的方式显示 CPU 利用率和饱和度,本篇文章重点为大家讲…

    Linux系统 2025年6月9日
  • tomcat 性能优化

    tomcat默认参数是为开发环境制定,而非适合生产环境,尤其是内存和线程的配置,默认都很低,容易成为性能瓶颈,本篇文章重点为大家讲解一下tomcat 性能优化。 Tomcat连接器…

    Linux系统 2025年10月6日
  • Linux下ulimit具体使用方法

    ulimit 是一个计算机命令,用于shell启动进程所占用的资源,可用于修改系统资源限制,本篇文章重点为大家分享一下Linux下ulimit具体使用方法,有需要的小伙伴可以参考一…

    Linux系统 2025年7月3日
  • Linux下安装autossh

    autossh 是一款开源工具,可以帮助管理SSH会话、自动重连和停止转发流量。autossh会假定目标主机已经设定无密码SSH登陆,以便autossh可以重连断开的SSH会话而不…

    Linux系统 2025年9月19日

发表回复

登录后才能评论