查看原文
其他

Python代码调试的那些“最少且必要”技巧

脚本之家 2021-06-30

脚本之家

你与百万开发者在一起


异常处理模块能帮助我们在运行期间处理异常信息,但Python代码还有更为基础的错误——语法错误和逻辑错误

语法错误相对简单,在解释器的帮助下,我们很快就能定位错误所在。但对逻辑错误的调试就难多了,这些语法或逻辑层面的错误,构成了各式各样的代码bug。

为了调试错误,我们需要知道,出错时哪些变量的值是正确的,哪些变量的值是错误的。因此,我们需要掌握一些代码调试的基本技巧。


本文选自《Python极简讲义:一本书入门数据分析与机器学习》一书。这是一本图文并茂、简单易读的Python极简讲义,以掌握“最少必要知识”为写作理念,对初学者十分友好!


01 利用print()输出观察变量

第一种方法,简单而有效,直接而粗暴,就是用print()把需要观察的变量打印出来,如下所示。

【例1】 print()输出观察变量(print-err.py)

01   def foo(s):
02       n = int(s)                     #字符串转换为整型
03       print('n = {}'.format(n))   #输出观察变量n的值
04       return 10 / n
05   
06   foo('0')


运行结果

n = 0
---------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
……
<ipython-input-9-d21f20e5d17e> in foo(s)
      2     n = int(s)
      3     print('n = {}'.format(n))
----> 4     return 10 / n
      5 
      6 def main():
ZeroDivisionError: division by zero


根据打印处的信息(第3行)和错误信息(division by zero),我们可以很容易地定位错误所在:代码第4行,作为分母,n值为0。

02  assert断言

用print()观察变量的不足之处在于,调试完毕后,我们还得手动将它们删掉,如果调试工作量较大,造成print()满天飞,删除大量print()语句的工作量也不容小觑。而且,如果程序中到处充斥着print()语句,输出信息也会非常繁杂,给程序员造成困扰。

因此,就有了第二种方法—断言(assert)。凡是可用print()来辅助查看的,都可以用assert来替代。它用来测试某个条件(condition)的布尔值,系统默认这个条件为真,此时断言悄然无息,我们感知不到它的存在。但是,一旦条件为假,就会触发异常。assert的语法格式如下。

assert <condition>   #第一种情况,不给出错误信息


在Python中,可以把assert理解为简化版的异常处理,它与如下语句等价。

if not <condition>    
   raise AssertionError


assert后面也可以紧跟参数,给出更为详细的错误信息,示例如下。

assert <condition> [, arguments]     #第二种情况,给出错误信息(可选项)


这种情况等价于如下语句。

if not condition:
    raise AssertionError(arguments)


下面我们通过具体示例来说明assert的用法,见【例2】。

【例2】assert的用法(assert_no_err_msg.py)

01   def avg(score):
02       assert len(score) != 0
03       return sum(score) / len(score)
04   
05   score = []
06   print("平均分数为:",avg(score))


运行结果

AssertionError                            Traceback (most recent call last)
<ipython-input-11-56d552b0cddd> in <module>
      4 
      5 score = []
----> 6 print("平均分数为:",avg(score))
<ipython-input-11-56d552b0cddd> in avg(score)
      1 def avg(score):
----> 2     assert len(score) != 0
      3     return sum(score)/len(score)
      4 
      5 score = []
AssertionError:


代码分析

由于代码的第05行是一个空列表,其长度为0,因此会让第02行的判断条件len(score) != 0 为假,这时就会触发异常,导致程序终止运行。此时,如果将第05行代码修改如下:

05   score = [90,85,78]


整个程序将能正常运行,运行结果如下。

平均分数为: 84.33333333333333


使用assert的好处在于,当判断条件为真时,用户是感觉不到assert的,因为assert只有当判断条件为假时才“刷存在感”,给出错误信息。错误信息一旦给出,在某种程度上就定位了代码的bug所在,从而达到了程序调试的目的。调试完毕后,用户无须删除assert语句。

【例2】中的assert并没有给出错误信息,可读性不强。事实上,我们还可以显式给出错误信息。我们可以如下修改【例2】的第02行代码。

assert len(marks) != 0, "列表为空,咋整啊!"


这里,断言条件后面的"列表为空,咋整啊!",就是条件一旦为假时输出的错误信息。我们假设,此时第05行依然为空列表,这时【例2】的运行结果如下。

AssertionError                            Traceback (most recent call last)
<ipython-input-13-a477886d663d> in <module>
      5 score = []
      6 # score = [90,85,78]
----> 7 print("平均分数为:",avg(score))
<ipython-input-13-a477886d663d> in avg(score)
      1 def avg(score):
----> 2     assert len(score) != 0,  "列表为空,咋整啊!"
      3     return sum(score) / len(score)
      4 
      5 score = []
AssertionError: 列表为空,咋整啊!

很明显,有了错误信息,就更容易找到代码的错误所在了。

如果断言太多,也会遭遇与print()类似的处境,异常信息会让我们“应接不暇”。如果不需要断言来帮忙,则在命令行启动Python解释器时可用“-O”参数来关闭assert,如下。

python -O assert_no_err_msg.py    #选项是大写的字母O,而非数字0




除了前面提到的利用print()、assert进行调试,我们还可以使用IDE(如PyCharm等)进行调试,这些集成开发环境有着非常好用的“单步调试功能”,同时配合控制台的输出,也能比较便捷地定位错误。

当我们开发的项目规模比较大时,我们会发现,logging才是终极武器。logging是Python的日志模块。使用这个模块的好处在于,它允许我们指定记录信息的级别,有debug、info、warning、error等。

我们可以根据需要输出不同级别的信息。例如,当我们指定level=INFO时,logging.debug就不起作用了。同理,指定level=WARNING后,debug和info就不起作用了。这样一来,我们就不必担心太多输出信息会冲淡关注力。

关于这个模块的知识,就留给“爱折腾”读者自学吧。高手,永远都是自学出来的!

相关图书

《Python极简讲义:一本书入门数据分析与机器学习》是一本理论结合实战,娓娓道来的入门好书。书中提供了入门数据科学领域的 极简必要知识 

不同于其他图书,本书不求全,但求精。这里的“精”是指,给出入门数据分析的“极简必要知识"( Minimal Actionable Knowledge and Experience,MAKE )。在极短的时间内,掌握数据分析的MAKE之道,这是本书的一大特色。

本书脉络


大咖推荐

  • 董付国,知名Python讲者、16本Python系列图书作者
  • 魏梦舒,微信公众号“程序员小灰”作者、《漫画算法》作者
  • 高扬博士,《白话强化学习与PyTorch》作者、金山办公AI技术专家
  • July,CSDN千万级流量博主、七月在线CEO
  • 雷明,SIGAI创始人、《机器学习:原理、算法与应用》作者、百度前高级软件工程师



小编为我们喜爱阅读的书迷们免费送书。




留言点赞送书活动规则


留言点赞:留言分享您在学习或者使用python开发过程中的学习经验,或者其他一些学习经历。


>>> 活动参与玩法1:机会总是靠自己去争取来的!小编将对留言进行精选,被精选的评论将会显示在页面中(由于微信功能限制,最多只能显示100条)。活动截止时获得点赞数最多的前2名朋友获得《Python极简讲义:一本书入门数据分析与机器学习》纸质书1本。玩法2:踩楼送书活动,活动结束时踩中已放在百度云文件中指定楼层的精选留言将获得《Python极简讲义:一本书入门数据分析与机器学习》一本,共3名中奖者,动结束后我们会在本公众号公布中奖楼层的解压密码


获奖楼层下载地址(文件解压密码会在2020年5月12日推送的中奖文章中公布)

百度云链接: 

https://pan.baidu.com/s/1i_WGN3QG02iKRWFJ7-RwKw 

提取码: kx5h

特别申明:

1、一位用户1个月内只能有1次获奖机会,让更多粉丝受益活动才更有意义

2、每一位用户只有1次留言机会,不允许重复留言~

请大家记住这三个1


活动截止时间:2020 年 05 月 12日 16:00 整。


精选书单 点蓝字即可 


 程序员的人生必做100件事中,一定有读这14本经典!

 程序员该怎么规划自己的成长路径?

 去年最畅销的IT类新书《漫画算法》出Python版了!

 如何用Python画一只机器猫?

 “Flutter中文网”社区创始人倾力撰写的网红书《Flutter实战》正式出版

 重磅 |《携程架构实践》《携程人工智能实践》上市啦!

 Python对我下手了!如何克服从入门到放弃?

更多好书请关注脚本之家官方书店

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

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