【发布时间】:2019-08-25 06:58:15
【问题描述】:
关于 SO 的相关问题(今天早些时候由我本人提出):Why does error traceback show edited script instead of what actually ran? 现在我知道为什么会发生这种情况,那么我现在想如何处理它。
我看到一些问题,如 How do I debug efficiently with spyder in Python? 和 How do I print debug messages in the Google Chrome JavaScript Console? 很受欢迎,所以我想询问调试实践是一个话题,对吧?
背景
我编写了一个在 n 行引发异常的脚本,从终端运行它,在脚本仍在运行时在中间添加一行,然后保存修改后的文件。所以脚本文件在解释器运行时被修改。特别是会引发异常的行的行号已经改变。 Python 解释器的错误回溯报告向我显示了脚本“修改”版本的第 n 行,而不是实际的“运行”版本。
小例子
假设我运行一个脚本:
import time
time.sleep(5)
raise Exception
当解释器卡在time.sleep(5) 时,我在后面添加了一行。
所以现在我有:
import time
time.sleep(5)
print("Hello World")
raise Exception
然后解释器从睡眠中醒来,执行下一条命令raise Exception,程序以以下回溯终止。
回溯(最近一次通话最后一次):
中的文件“test/minimal_error.py”,第 4 行 打印(“你好世界”)
例外
所以它正确地报告了行号(来自 original 脚本,所以如果我们只有修改过的脚本实际上是无用的)和错误消息(“异常”)。但它显示了实际上引发错误的完全错误的代码行;如果它有任何帮助,应该显示raise Exception,而不是print("Hello World"),它甚至没有被解释器执行。
为什么这很重要
在实际实践中,我实现了程序的一个部分,运行它以查看该部分是否运行良好,当它仍在运行时,我继续执行下一个我必须实现的事情。当脚本抛出错误时,我必须找出导致错误的实际代码行。我通常只是阅读错误信息并尝试推断导致它的原始代码。
有时不容易猜到,所以我将脚本复制到剪贴板并通过在运行脚本后撤消我编写的内容来回滚代码,检查导致错误的行,然后从剪贴板粘贴回来。有时这很烦人,因为当我运行它时,并不总是能记住脚本的确切状态。 (“我是否需要撤消更多操作才能回滚?或者这正是我运行的脚本?”)
有时脚本会运行超过 10 分钟,甚至是一个小时,然后才会引发异常。在这种情况下,“通过撤消回滚”实际上是不可能的。有时我什至不知道脚本在实际运行之前会运行多长时间。我显然不能在脚本终止之前坐下来保持脚本不被修改。
问题
通过什么做法我可以正确追踪导致异常的命令?
一个假设的解决方案是每次我想运行脚本时都将它复制到一个新文件中,运行复制的版本,然后继续编辑原始版本。但是我觉得这太麻烦了,不能每十分钟做一次,每当我需要运行一个脚本来看看它是否运行良好时。
另一种方法是每次我想运行它时都git-commit,这样我可以在需要的时候回来查看原始版本,但这会使提交历史非常脏,所以我认为这比另一个更糟糕。
我也尝试了python -m pdb -m script.py,但它显示了相同的“行 n 的修改版本”,就像普通的回溯一样。
那么有什么实用的解决方案可以让我练习,比如每十分钟练习一次吗?
【问题讨论】:
-
您不会从您发布的代码中获得该回溯,至少不是来自新导入的模块,或者如果您将其作为脚本运行。引发异常的行是
raise Exception。 -
@chepner,我从
python test.py等终端运行脚本(没有print(...)行),然后在解释器卡在time.sleep(5)时添加print(...)行,保存脚本,解释器完成睡眠并到达raise,因此引发异常,并且回溯显示带有print(...)的行。我想我在“最小示例”中说清楚了,但如果我没有说清楚,我很抱歉。你觉得我怎样才能说得更清楚? -
我很确定实际的解决方案是“不要这样做”。不要修改正在运行的代码。
-
你可以写一些东西来自动化你假设的解决方案。
mktemp可能有用。