python - 为什么错误回溯显示已编辑的脚本而不是实际运行的脚本?

标签 python interpreter

背景

考虑以下最小示例:

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

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 秒 sleep 期间,我在中间添加一行。

import time

time.sleep(5)
a = 1
raise Exception

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

Traceback (most recent call last):
  File "test/minimal_error.py", line 4, in <module>
    a = 1
Exception

所以明显的问题是它没有打印导致错误的实际代码。虽然它给出了正确的行号(正确反射(reflect)了正在运行的脚本的版本,但可以理解是无用的)和正确的错误消息,但我真的不知道究竟是哪段代码导致了错误。

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

问题

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

我不太确定这个问题在这里是否切合主题,但我不认为我可以根据 help center 的内容得出结论。说。它是关于“程序员常用的 [一种] 软件 [工具]”(Python 解释器)并且是“软件开发独有的一个实用的、可回答的问题,”我认为。我不认为它是基于意见的,因为选择这种实现方式应该是有原因的。

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

最佳答案

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

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

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

关于python - 为什么错误回溯显示已编辑的脚本而不是实际运行的脚本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55492150/

相关文章:

python - 此条件的 Pandas DataFrame 样式

python - 成对求和的运行时间复杂度是多少?

python - python中变量是如何创建和销毁的?

java - 模拟 java.lang.Thread 的最佳方法是什么?

Python (pygame) Sin、Cos 和 Tan

python - pyparsing 如何跳过缩进 block 的结尾?

python - 只有单线程使用多处理池执行与PySpark的并行SQL查询

python - OS X 终端中 Python 解释器中的制表符补全

python - Python 的 __init__(self) 方法是否在所有其他类/实例方法之前由解释器定义?

c# - 需要 .Net 的公式解释器