Python编程为什么不使用print调试代码了

技术Python编程为什么不使用print调试代码了这篇文章主要介绍“Python编程为什么不使用print调试代码了”,在日常操作中,相信很多人在Python编程为什么不使用print调试代码了问题上存在疑惑,小编查阅

本文主要介绍“Python编程为什么不用打印调试代码”。在日常操作中,相信很多人对Python编程为什么不用print调试代码有疑问。边肖查阅了各种资料,整理出简单易用的操作方法,希望能帮你解决“Python编程为什么不用print调试代码”的疑惑!接下来,请和边肖一起学习!

00-1010执行以下命令安装PySnooper。

$python3-mpipinstallpysnooper

#或者

$ condainstall-cconda-forgepysnooper

#或者

$yay-Spython-pysnooper

1. 快速安装

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

代码本身没有实际意义,但足以演示PySnooper。

importpysnooper

@pysnooper.snoop()

defdemo_func():

个人资料={}

简介['名称']='编写代码的明歌'

简介【‘年龄’】=27岁

简介['性别']='男性'

返回配置文件

defmain():

profile=demo_func()

Main()现在我使用终端命令行来运行它。

[root@iswbm~]#python3demo.py

Sourcepath:演示

17:523:49 . 624943 call 4 defdemo _ func().

17:52:49 . 625124 line 5 profile={ }

Newvar:个人资料={}

我们的line6profile ['name']='编写代码的明歌'。56660 . 66666666666

修改后的var :profile={'name' : '编写代码的明歌' }。

17:52:49 . 625207 line 7 profile[' age ']=27

修改后的var :profile={'name' : '编写代码的明歌',' age':27}

17:52:49 . 625254 line 8 profile['性别']='男性'

修改后的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"] 值有变化时,也将其打印出来

Python编程为什么不使用print调试代码了

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

效果如下

Python编程为什么不使用print调试代码了

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

效果如下

Python编程为什么不使用print调试代码了

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"<Person {obj.name} {obj.age} {obj.gender}>"
  
@pysnooper.snoop(custom_repr=(Person, print_person_obj))
def demo_func():
    ...

完整的代码如下

import pysnooper
class Person:pass
def print_person_obj(obj):
    return f"<Person {obj.name} {obj.age} {obj.gender}>"
@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()

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

Python编程为什么不使用print调试代码了

如果你要自定义格式输出的有很多个类型,那么 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():
    ...

到此,关于“Python编程为什么不使用print调试代码了”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/47498.html

(0)

相关推荐

  • Solr4.7如何使用分组查询方面

    技术solr4.7分组查询facet怎么使用本篇内容主要讲解“solr4.7分组查询facet怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“solr4.7分组查询fa

    攻略 2021年12月22日
  • 怎么解决Oracle数据库中未清空磁盘被添加到磁盘组触发坏块问题

    技术怎么解决Oracle数据库中未清空磁盘被添加到磁盘组触发坏块问题这篇文章主要介绍“怎么解决Oracle数据库中未清空磁盘被添加到磁盘组触发坏块问题”,在日常操作中,相信很多人在怎么解决Oracle数据库中未清空磁盘被

    攻略 2021年11月5日
  • 民族团结小故事100字,民族团结小故事450字

    技术民族团结小故事100字,民族团结小故事450字中国巾帼英雄第一人冼夫人她的生平被载入籍《二十五史》的《隋书》、《北史》和《资治通鉴》民族团结小故事100字。她的英雄形象依然深深地刻在中国人民心中,被陈、隋皇朝敕封为“

    生活 2021年10月29日
  • 安装实时监控mysql开源工具GitHub orzdba的操作方法

    技术安装实时监控mysql开源工具GitHub orzdba的操作方法这期内容当中小编将会给大家带来有关安装实时监控mysql开源工具GitHub orzdba的操作方法,文章内容丰富且以专业的角度为大家分析和叙述,阅读

    攻略 2021年10月29日
  • 373. 查找和最小的K对数字

    技术373. 查找和最小的K对数字 373. 查找和最小的K对数字给定两个以升序排列的整数数组 nums1 和 nums2,以及一个整数 k。
    定义一对值(u,v),其中第一个元素来自nums1,第二个

    礼包 2021年12月16日
  • Python中如何实现数据库操作

    技术Python中如何实现数据库操作这篇文章主要为大家展示了“Python中如何实现数据库操作”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Python中如何实现数据库操作”

    攻略 2021年10月28日