为什么错误回溯显示已编辑的脚本而不是实际 运行?
Why does error traceback show edited script instead of what actually ran?
背景
考虑以下最小示例:
当我保存以下脚本并从终端 运行 时,
import time
time.sleep(5)
raise Exception
代码将在休眠五秒后引发错误,并留下以下回溯。
Traceback (most recent call last):
File "test/minimal_error.py", line 4, in <module>
raise Exception
Exception
现在,比方说,我 运行 脚本,在 5 秒睡眠期间,我在中间添加了一行。
import time
time.sleep(5)
a = 1
raise Exception
在 python 解释器从睡眠中醒来并到达下一行 raise Exception
后,它会引发错误,但会留下以下回溯。
Traceback (most recent call last):
File "test/minimal_error.py", line 4, in <module>
a = 1
Exception
所以明显的问题是它没有打印导致错误的实际代码。虽然它给出了正确的行号(正确反映了 运行ning 的脚本版本,但毫无用处是可以理解的)和正确的错误消息,但我真的不知道是哪段代码真正导致了错误。
在实际操作中,我实现了一个程序的一部分,运行 它是为了查看该部分是否运行良好,当它仍然是 运行ning 时,我继续进行下一个我必须实施的事情。当脚本抛出错误时,我必须找到导致错误的实际代码行。我通常只是阅读错误消息并尝试推断导致它的原始代码。有时不容易猜到,所以我将脚本复制到剪贴板并通过撤消我在 运行 脚本后编写的代码来回滚代码,检查导致错误的行,然后从剪贴板粘贴回来。
问题
为什么解释器显示 a = 1
,即 "current" 版本代码的第 4 行,而不是 raise Exception
,即代码的第 4 行,有什么可以理解的原因吗? "running" 代码的版本?如果解释器知道 "line 4" 导致错误并且错误消息是 "Exception",为什么它不能说命令 raise Exception
引发了错误?
我不太确定这个问题在这里是否切合主题,但我认为我不能从 help center 所说的内容得出结论。它是关于“程序员常用的 [一种] 软件 [工具]”(Python 解释器),我认为是 "a practical, answerable problem that is unique to software development,"。我不认为这是基于意见的,因为选择这种实现方式应该是有原因的。
(在 Python 2.7.16、3.6.8、3.7.2 和 3.7.3 中观察到相同的情况,所以它似乎不是特定于版本的,而是刚刚发生的事情在 Python.)
直接原因是Python重新打开文件并再次读取指定行以在错误消息中打印它。那么为什么它在一开始就已经读取了文件时还需要这样做呢?因为它不在内存中保存源代码,只保存生成的字节码。
事实上,Python 永远不会一次将源文件的全部内容保存在内存中。相反,词法分析器将从文件中读取并一次生成一个标记,然后解析器将其解析并转换为字节码。一旦解析器完成了令牌,它就消失了。
因此,返回原始源代码的唯一方法是再次打开源文件。
我认为这是描述的经典问题here。
睡眠使用 os 系统调用来暂停该线程的执行。
背景
考虑以下最小示例:
当我保存以下脚本并从终端 运行 时,
import time
time.sleep(5)
raise Exception
代码将在休眠五秒后引发错误,并留下以下回溯。
Traceback (most recent call last):
File "test/minimal_error.py", line 4, in <module>
raise Exception
Exception
现在,比方说,我 运行 脚本,在 5 秒睡眠期间,我在中间添加了一行。
import time
time.sleep(5)
a = 1
raise Exception
在 python 解释器从睡眠中醒来并到达下一行 raise Exception
后,它会引发错误,但会留下以下回溯。
Traceback (most recent call last):
File "test/minimal_error.py", line 4, in <module>
a = 1
Exception
所以明显的问题是它没有打印导致错误的实际代码。虽然它给出了正确的行号(正确反映了 运行ning 的脚本版本,但毫无用处是可以理解的)和正确的错误消息,但我真的不知道是哪段代码真正导致了错误。
在实际操作中,我实现了一个程序的一部分,运行 它是为了查看该部分是否运行良好,当它仍然是 运行ning 时,我继续进行下一个我必须实施的事情。当脚本抛出错误时,我必须找到导致错误的实际代码行。我通常只是阅读错误消息并尝试推断导致它的原始代码。有时不容易猜到,所以我将脚本复制到剪贴板并通过撤消我在 运行 脚本后编写的代码来回滚代码,检查导致错误的行,然后从剪贴板粘贴回来。
问题
为什么解释器显示 a = 1
,即 "current" 版本代码的第 4 行,而不是 raise Exception
,即代码的第 4 行,有什么可以理解的原因吗? "running" 代码的版本?如果解释器知道 "line 4" 导致错误并且错误消息是 "Exception",为什么它不能说命令 raise Exception
引发了错误?
我不太确定这个问题在这里是否切合主题,但我认为我不能从 help center 所说的内容得出结论。它是关于“程序员常用的 [一种] 软件 [工具]”(Python 解释器),我认为是 "a practical, answerable problem that is unique to software development,"。我不认为这是基于意见的,因为选择这种实现方式应该是有原因的。
(在 Python 2.7.16、3.6.8、3.7.2 和 3.7.3 中观察到相同的情况,所以它似乎不是特定于版本的,而是刚刚发生的事情在 Python.)
直接原因是Python重新打开文件并再次读取指定行以在错误消息中打印它。那么为什么它在一开始就已经读取了文件时还需要这样做呢?因为它不在内存中保存源代码,只保存生成的字节码。
事实上,Python 永远不会一次将源文件的全部内容保存在内存中。相反,词法分析器将从文件中读取并一次生成一个标记,然后解析器将其解析并转换为字节码。一旦解析器完成了令牌,它就消失了。
因此,返回原始源代码的唯一方法是再次打开源文件。
我认为这是描述的经典问题here。
睡眠使用 os 系统调用来暂停该线程的执行。