print语句|Python 七步捉虫法


print语句|Python 七步捉虫法文章插图
了解一些技巧助你减少代码查错时间 。
-- Maria Mckinley
在周五的下午三点钟(为什么是这个时间?因为事情总会在周五下午三点钟发生) , 你收到一条通知 , 客户发现你的软件出现一个错误 。 在有了初步的怀疑后 , 你联系运维 , 查看你的软件日志以了解发生了什么 , 因为你记得收到过日志已经搬家了的通知 。
结果这些日志被转移到了你获取不到的地方 , 但它们正在导入到一个网页应用中——所以到时候你可以用这个漂亮的应用来检索日志 , 但是 , 这个应用现在还没完成 。 这个应用预计会在几天内完成 。 我知道 , 你觉得这完全不切实际 。 然而并不是 , 日志或者日志消息似乎经常在错误的时间消失不见 。 在我们开始查错前 , 一个忠告:经常检查你的日志以确保它们还在你认为它们应该在的地方 , 并记录你认为它们应该记的东西 。 当你不注意的时候 , 这些东西往往会发生令人惊讶的变化 。
好的 , 你找到了日志或者尝试了呼叫运维人员 , 而客户确实发现了一个错误 。 甚至你可能认为你已经知道错误在哪儿 。
你立即打开你认为可能有问题的文件并开始查错 。
1、先不要碰你的代码阅读代码 , 你甚至可能会想到该阅读哪些部分 。 但是在开始搞乱你的代码前 , 请重现导致错误的调用并把它变成一个测试 。 这将是一个集成测试 , 因为你可能还有其他疑问 , 目前你还不能准确地知道问题在哪儿 。
确保这个测试结果是失败的 。 这很重要 , 因为有时你的测试不能重现失败的调用 , 尤其是你使用了可以混淆测试的 web 或者其他框架 。 很多东西可能被存储在变量中 , 但遗憾的是 , 只通过观察测试 , 你在测试里调用的东西并不总是明显可见的 。 当我尝试着重现这个失败的调用时 , 我并不是说我要创建一个可以通过的测试 , 但是 , 好吧 , 我确实是创建了一个测试 , 但我不认为这特别不寻常 。
从自己的错误中吸取教训 。
2、编写错误的测试现在 , 你有了一个失败的测试 , 或者可能是一个带有错误的测试 , 那么是时候解决问题了 。 但是在你开干之前 , 让我们先检查下调用栈 , 因为这样可以更轻松地解决问题 。
调用栈包括你已经启动但尚未完成地所有任务 。 因此 , 比如你正在烤蛋糕并准备往面糊里加面粉 , 那你的调用栈将是:

  • 做蛋糕
  • 打面糊
  • 加面粉
你已经开始做蛋糕 , 开始打面糊 , 而你现在正在加面粉 。 往锅底抹油不在这个列表中 , 因为你已经完成了 , 而做糖霜不在这个列表上因为你还没开始做 。
如果你对调用栈不清楚 , 我强烈建议你使用 Python Tutor, 它能帮你在执行代码时观察调用栈 。
现在 , 如果你的 Python 程序出现了错误 ,Python 解释器会帮你打印出当前调用栈 。 这意味着无论那一时刻程序在做什么 , 很明显错误发生在调用栈的底部 。
3、始终先检查调用栈底部在栈底你不仅能看到发生了哪个错误 , 而且通常可以在调用栈的最后一行发现问题 。 如果栈底对你没有帮助 , 而你的代码还没有经过代码分析 , 那么使用代码分析是非常有用的 。 我推荐 pylint 或者 flake8 。 通常情况下 , 它会指出我一直忽略的错误的地方 。
如果错误看起来很迷惑 , 你下一步行动可能是用 Google 搜索它 。 如果你搜索的内容不包含你的代码的相关信息 , 如变量名、文件等 , 那你将获得更好的搜索结果 。 如果你使用的是 Python 3(你应该使用它) , 那么搜索内容包含 Python 3 是有帮助的 , 否则 Python 2 的解决方案往往会占据大多数 。
很久以前 , 开发者需要在没有搜索引擎的帮助下解决问题 。 那是一段黑暗时光 。 充分利用你可以使用的所有工具 。
不幸的是 , 有时候问题发生在更早阶段 , 但只有在调用栈底部执行的地方才显现出来 。 就像当蛋糕没有膨胀时 , 忘记加发酵粉的事才被发现 。
那就该检查整个调用栈 。 问题更可能在你的代码而不是 Python 标准库或者第三方包 , 所以先检查调用栈内你的代码 。 另外 , 在你的代码中放置断点通常会更容易检查代码 。 在调用栈的代码中放置断点 , 然后看看周围是否如你预期 。
“但是 , 玛丽 , ”我听到你说 , “如果我有一个调用栈 , 那这些都是有帮助的 , 但我只有一个失败的测试 。 我该从哪里开始?”
pdb , 一个 Python 调试器 。