为什么错误跟踪显示已编辑的脚本而不是实际运行的脚本?

时间:2019-04-03 09:50:34

标签: python interpreter

背景

请考虑以下最小示例:

当我保存以下脚本并从终端运行它时,

import time

time.sleep(5)
raise Exception

该代码将在睡眠五秒钟后引发错误,并留下以下回溯。

  

回溯(最近通话最近):
  <模块>
中的文件“ test / minimal_error.py”,第4行   引发异常
  例外

现在,我运行脚本,在5秒钟的睡眠期间,在中间添加一行。

import time

time.sleep(5)
a = 1
raise Exception

在python解释器从睡眠中唤醒并到达下一行raise Exception之后,它将引发错误,但会留下以下回溯。

  

回溯(最近通话最近):
  <模块>
中的文件“ test / minimal_error.py”,第4行   a = 1
  例外

因此,一个明显的问题是它不会打印出导致错误的实际代码。尽管它提供了正确的行号(正确地反映了正在运行的脚本的版本,虽然可以理解地没有用)和正确的错误消息,但我真的不知道是哪段代码真正导致了错误。

在实际实践中,我实现了程序的一部分,运行该程序以查看该部分是否运行良好,并且在该程序仍在运行时,我继续进行下一步。当脚本引发错误时,我必须找到导致错误的实际代码行。我通常只是阅读错误消息,然后尝试推断出导致该错误的原始代码。有时很难猜测,因此我将脚本复制到剪贴板中,并通过撤消运行脚本后编写的内容来回滚代码,检查导致错误的行,然后从剪贴板粘贴回去。

问题

解释器显示a = 1(这是代码的“当前”版本的第4行)而不是raise Exception(这是“运行”版本的第4行)有任何可以理解的原因吗?代码?如果解释器知道“ 4行”引起了错误,并且错误消息为“ Exception”,为什么它不能说命令raise Exception引发了该错误?

我不太确定这个问题是否在这里是话题性的,但我认为我无法根据help center的说法得出结论。我想这是关于“程序员通常使用的[a]软件[tool]”(Python解释器),并且是“对于软件开发来说是一个实际的,可回答的问题,”。我认为这不是基于意见的,因为应该选择这种实施方式。

(在Python 2.7.16、3.6.8、3.7.2和3.7.3中观察到相同,因此它似乎不是特定于版本的,而是在Python中发生的事情。)

2 个答案:

答案 0 :(得分:5)

直接原因是Python重新打开文件并再次读取指定的行以在错误消息中打印它。那么,为什么一开始就已经读取了文件,为什么还要这样做呢?因为它不会将源代码保留在内存中,所以只能生成生成的字节码。

实际上,Python永远不会一次将源文件的全部内容保存在内存中。相反,词法分析器将从文件中读取一次并生成一个令牌,然后解析器解析该令牌并将其转换为字节码。使用令牌完成解析器后,它就消失了。

所以返回原始源代码的唯一方法是再次打开源文件。

答案 1 :(得分:0)

我认为这是一个here所描述的经典问题。

使用os系统调用休眠以暂停该线程的执行。