在周五的下午三点钟(为何是这个时间?由于事情总会在周五下午三点钟发生),你收到一条通知,客户发现你的软件出现一个错误。在有了初步的怀疑后,你联系运维,查看你的软件日志以了解发生了什么,由于你记得收到过日志已经搬家了的通知。 |
结果这些日志被转移到了你获取不到的地方,但它们正在导入到一个网页应用中——因此到时候你能够用这个漂亮的应用来检索日志,可是,这个应用如今还没完成。这个应用预计会在几天内完成。我知道,你以为这彻底不切实际。然而并非,日志或者日志消息彷佛常常在错误的时间消失不见。在咱们开始查错前,一个忠告:常常检查你的日志以确保它们还在你认为它们应该在的地方,并记录你认为它们应该记的东西。当你不注意的时候,这些东西每每会发生使人惊讶的变化。html
好的,你找到了日志或者尝试了呼叫运维人员,而客户确实发现了一个错误。甚至你可能认为你已经知道错误在哪儿。python
你当即打开你认为可能有问题的文件并开始查错。linux
一、先不要碰你的代码web
阅读代码,你甚至可能会想到该阅读哪些部分。可是在开始搞乱你的代码前,请重现致使错误的调用并把它变成一个测试。这将是一个集成测试,由于你可能还有其余疑问,目前你还不能准确地知道问题在哪儿。安全
确保这个测试结果是失败的。这很重要,由于有时你的测试不能重现失败的调用,尤为是你使用了能够混淆测试的 web 或者其余框架。不少东西可能被存储在变量中,但遗憾的是,只经过观察测试,你在测试里调用的东西并不老是明显可见的。当我尝试着重现这个失败的调用时,我并非说我要建立一个能够经过的测试,可是,好吧,我确实是建立了一个测试,但我不认为这特别不寻常。从本身的错误中吸收教训。网络
二、编写错误的测试框架
如今,你有了一个失败的测试,或者多是一个带有错误的测试,那么是时候解决问题了。可是在你开干以前,让咱们先检查下调用栈,由于这样能够更轻松地解决问题。运维
调用栈包括你已经启动但还没有完成地全部任务。所以,好比你正在烤蛋糕并准备往面糊里加面粉,那你的调用栈将是:函数
作蛋糕 打面糊 加面粉
你已经开始作蛋糕,开始打面糊,而你如今正在加面粉。往锅底抹油不在这个列表中,由于你已经完成了,而作糖霜不在这个列表上由于你还没开始作。工具
若是你对调用栈不清楚,我强烈建议你使用 Python Tutor,它能帮你在执行代码时观察调用栈。
如今,若是你的 Python 程序出现了错误, Python 解释器会帮你打印出当前调用栈。这意味着不管那一时刻程序在作什么,很明显错误发生在调用栈的底部。
三、始终先检查调用栈底部
在栈底你不只能看到发生了哪一个错误,并且一般能够在调用栈的最后一行发现问题。若是栈底对你没有帮助,而你的代码尚未通过代码分析,那么使用代码分析是很是有用的。我推荐 pylint 或者 flake8。一般状况下,它会指出我一直忽略的错误的地方。
若是错误看起来很迷惑,你下一步行动多是用 Google 搜索它。若是你搜索的内容不包含你的代码的相关信息,如变量名、文件等,那你将得到更好的搜索结果。若是你使用的是 Python 3(你应该使用它),那么搜索内容包含 Python 3 是有帮助的,不然 Python 2 的解决方案每每会占据大多数。
好久之前,开发者须要在没有搜索引擎的帮助下解决问题。那是一段黑暗时光。充分利用你可使用的全部工具。
不幸的是,有时候问题发生在更早阶段,但只有在调用栈底部执行的地方才显现出来。就像当蛋糕没有膨胀时,忘记加发酵粉的事才被发现。
那就该检查整个调用栈。问题更可能在你的代码而不是 Python 标准库或者第三方包,因此先检查调用栈内你的代码。另外,在你的代码中放置断点一般会更容易检查代码。在调用栈的代码中放置断点,而后看看周围是否如你预期。
“可是,玛丽,”我听到你说,“若是我有一个调用栈,那这些都是有帮助的,但我只有一个失败的测试。我该从哪里开始?”
pdb,一个 Python 调试器。
找到你代码里会被这个调用命中的地方。你应该可以找到至少一个这样的地方。在那里打上一个 pdb 的断点。
一句题外话
为何不使用 print 语句呢?我曾经依赖于 print 语句。有时候,它们仍然很方便。但当我开始处理复杂的代码库,尤为是有网络调用的代码库,print 语句就变得太慢了。我最终在各类地方都加上了 print 语句,但我无法追踪它们的位置和缘由,并且变得更复杂了。可是主要使用 pdb 还有一个更重要的缘由。假设你添加一条 print 语句去发现错误问题,并且 print 语句必须早于错误出现的地方。可是,看看你放 print 语句的函数,你不知道你的代码是怎么执行到那个位置的。查看代码是寻找调用路径的好方法,但看你之前写的代码是恐怖的。是的,我会用 grep 处理个人代码库以寻找调用函数的地方,但这会变得乏味,并且搜索一个通用函数时并不能缩小搜索范围。pdb 就变得很是有用。
你遵循个人建议,打上 pdb 断点并运行你的测试。然而测试再次失败,可是没有任何一个断点被命中。留着你的断点,并运行测试套件中一个同这个失败的测试很是类似的测试。若是你有个不错的测试套件,你应该可以找到一个这样的测试。它会命中了你认为你的失败测试应该命中的代码。运行这个测试,而后当它运行到你的断点,按下 w 并检查调用栈。若是你不知道如何查看由于其余调用而变得混乱的调用栈,那么在调用栈的中间找到属于你的代码,并在堆栈中该代码的上一行放置一个断点。再试一次新的测试。若是仍然没命中断点,那么继续,向上追踪调用栈并找出你的调用在哪里脱轨了。若是你一直没有命中断点,最后到了追踪的顶部,那么恭喜你,你发现了问题:你的应用程序名称拼写错了。没有经验,小白,一点都没有经验。
四、修改代码
若是你仍以为迷惑,在你稍微改变了一些的地方尝试新的测试。你能让新的测试跑起来么?有什么是不一样的呢?有什么是相同的呢?尝试改变一下别的东西。当你有了你的测试,以及可能也还有其它的测试,那就能够开始安全地修改代码了,肯定是否能够缩小问题范围。记得从一个新提交开始解决问题,以便于能够轻松地撤销无效地更改。(这就是版本控制,若是你没有使用过版本控制,这将会改变你的生活。好吧,可能它只是让编码更容易。查阅“版本控制可视指南”,以了解更多。)
五、休息一下
尽管如此,当它再也不感受起来像一个有趣的挑战或者游戏而开始变得使人沮丧时,你最好的举措是脱离这个问题。休息一下。我强烈建议你去散步并尝试考虑别的事情。
六、把一切写下来
当你回来了,若是你没有忽然受到启发,那就把你关于这个问题所知的每个点信息写下来。这应该包括:
真正形成问题的调用 真正发生了什么,包括任何错误信息或者相关的日志信息 你真正指望发生什么 到目前为止,为了找出问题,你作了什么工做;以及解决问题中你发现的任何线索。 有时这里有不少信息,但相信我,从零碎中挖掘信息是很烦人。因此尽可能简洁,可是要完整。
七、寻求帮助
我常常发现写下全部信息可以启迪我想到还没尝试过的东西。固然,有时候我在点击求助邮件(或表单)的提交按钮后马上意识到问题是是什么。不管如何,当你在写下全部东西仍一无所得时,那就试试向他人发邮件求助。首先是你的同事或者其余参与你的项目的人,而后是该项目的邮件列表。不要惧怕向人求助。大多数人都是友善和乐于助人的,我发如今 Python 社区里尤为如此。
原文来自:https://linux.cn/article-10603-1.html
本文地址:https://www.linuxprobe.com/python-learns-seven-steps.html编辑:冯瑞涛,审核员:逄增宝