查看原文
其他

对抗bug方法介绍——爆款pysnooper你用了吗?(下篇)

爬虫俱乐部 Stata and Python数据分析 2022-03-15

本文作者:张    邯

文字编辑:余术玲

技术总编:张    邯


 爬虫俱乐部将于2019年8月22日至28日湖北武汉举行为期一周的Stata编程技术定制培训,此次培训采用Stata16进行讲解,采取初级班和高级班分批次培训。课程通过案例教学模式,旨在帮助大家在短期内掌握Stata软件编程、金融计量知识和实证分析方法,使大家熟悉Stata核心的爬虫技术,以及Stata与其他软件交互的高端技术。目前正在火热招生中~

详细培训大纲及报名方式,请点击文末阅读原文呦~


 在上篇中,我们介绍了pysnooper作为装饰器加在一个函数前面来监听它,包括将日志输出到屏幕和文件中,今天我们介绍它的一种更为灵活的使用方法:作为一个上下文管理器(contextor)的使用方法。

上下文管理器是Python的黑魔法之一,如果经常使用Python处理日常工作的小伙伴可能使用过它,一个最简单的例子就是 “with open”,详细的工作原理和完整的知识我们将在以后的推文中专门介绍,这里只需要知道它的存在意义:有些工作需要事先设置、事后关闭清理,打开文件的open()就是其中之一,在文件操作完成后,要时刻记得将句柄关掉,但大段代码过后忘记清理是常有的事,这时候使用上下文管理器就可以贴心地帮你自动调用__exit__()方法(通常用于清理和关闭)。

今天的主角pysnooper也具有这样一个使用方法,生成一个上下文管理对象。当计算机遇到with pysnooper.snoop():时,先检查一遍当前内存内所有已有变量,并将它们作为新变量记录日志,即(New var:变量名 = 当前值),接下来在其中的所有代码的调用(call)、变量更新(Modified var)和变量新建(New var)都会被记录日志,直到在with 内的全部代码执行完毕,然后关闭监听,所以你可以将它放在任意几句你想监听的代码外面。

我们先来看一个例子:

def GetPrime(num): lst = [2] with pysnooper.snoop(): for i in range(3,num): flag = 1 for j in lst:         if i % j == 0 : flag = 0 ; break                   if flag : lst.append(i);print(f"{i}是质数")  GetPrime(5)

这个函数实现了查找num以内的所有质数,我们在循环前加一个上下文管理器,并且把我们要监听的循环放在其中(此处所有代码需全部再缩进一次),得到如下结果(信息的解读与上篇内容一致,不做赘述):

New var:....... num = 5New var:....... lst = [2]21:12:09.323558 line 19 for i in range(3,num):New var:....... i = 321:12:09.323558 line 20 flag = 1New var:....... flag = 121:12:09.324023 line 21 for j in lst:New var:....... j = 221:12:09.324023 line 22 if i % j == 0 : flag = 0 ; break21:12:09.324023 line 21 for j in lst:21:12:09.324023 line 19 for i in range(3,num):Modified var:.. i = 421:12:09.324023 line 20 flag = 121:12:09.324023 line 21 for j in lst:21:12:09.324521 line 22 if i % j == 0 : flag = 0 ; breakModified var:.. flag = 021:12:09.324521 line 19 for i in range(3,num):21:12:09.324521 line 24 if flag : lst.append(i);print(f"{i}是质数")

这里我们将监听的代码块从外层循环变成内层循环:

def GetPrime(num):   lst = [2]   for i in range(3,num): flag = 1 with pysnooper.snoop(): for j in lst:         if i % j == 0 : flag = 0 ; break                if flag : lst.append(i);print(f"{i}是质数")  GetPrime(5)

得到如下结果:

New var:....... num = 5New var:....... lst = [2]New var:....... i = 3New var:....... flag = 121:07:08.980698 line 22 for j in lst:New var:....... j = 221:07:08.981194 line 23 if i % j == 0 : flag = 0 ; break21:07:08.981194 line 22 for j in lst:3是质数New var:....... num = 5New var:....... lst = [2, 3]New var:....... i = 4New var:....... flag = 1New var:....... j = 221:07:08.981194 line 21 with pysnooper.snoop(): 21:07:08.981194 line        22          for j in lst:21:07:08.981194 line 23 if i % j == 0 : flag = 0 ; break

比较上下两个结果,我们可以得到一些思考:上例一共调用它一次,i的值每次更新(Modified),其他变量(如lst)的值直到有改变之前不会显示,而下例由于在内层循环,所以每次都是一次新的调用,在调用时,snoop() 会检查内存中所有的变量并作为新的变量记录日志,所以大家会发现i的值和列表lst两个变量被新建(New)了很多次,导致日志比之前多了很多报告变量的日志。所以,当程序体比较复杂的时候,如何选择我们想要检测的一段而将其他的变量状态忽略是我们需要重点考虑的。

 另外,它也有输出到文件和加前缀的参数,只需要参照上篇文章加入到括号中即可。除了基本用法之外,它也可以监听多线程和其他指定的非本地变量,感兴趣的读者可以自己在官网上阅读。虽然Pyecharts体量很小,但是它的设计非常简洁贴合实际需求,上手简单粗暴也易于理解,相信在开发者的不断维护下,它的前途不可估量,是个值得关注的第三方库~

对爬虫俱乐部的推文累计打赏超过1000元我们即可给您开具发票,发票类别为“咨询费”。用心做事,只为做您更贴心的小爬虫!

往期推文推荐

        Python基础之数字类型

         循环输出统计文件

关于我们

微信公众号“爬虫俱乐部”分享实用的stata命令,欢迎转载、打赏。爬虫俱乐部是由李春涛教授领导下的研究生及本科生组成的大数据分析和数据挖掘团队。

此外,欢迎大家踊跃投稿,介绍一些关于stata的数据处理和分析技巧。

投稿邮箱:statatraining@163.com

投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到关于stata分析数据的问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存