3

当 Python 解释器报告错误/异常时(从现在开始,我只想说“错误”来指代这两者),它会打印导致错误的行号和行的内容。

有趣的是,如果您有一个长时间运行的 Python 脚本导致错误并.py在脚本运行时更改文件,那么解释器可以根据文件更改的内容报告错误的行作为引发错误.py

MWE:

示例.py

from time import sleep

for i in range(10):
    print(i)
    sleep(1)

raise Exception("foo", "bar")

此脚本运行 10 秒,然后引发异常。

样本2.py

from time import sleep

for i in range(10):
    print(i)
    sleep(1)
"""
This
is
just
some
filler
to
demonstrate
the
behavior
"""
raise Exception("foo", "bar")

这个文件是相同的,sample.py只是它在循环结束之间有一些垃圾,并且该行引发了以下异常:

Traceback (most recent call last):
  File "sample.py", line 7, in <module>
Exception: ('foo', 'bar')

我做了什么

  1. python3 sample.py
  2. 在第二个终端窗口中,mv sample.py sample.py.bak && cp sample2.py sample.pysample.py完成执行之前

预期行为

口译员报告以下内容:

Traceback (most recent call last):
  File "sample.py", line 7, in <module>
Exception: ('foo', 'bar')

在这里,解释器报告第 7 行出现异常sample.py并打印异常。

实际行为

口译员报告以下内容:

Traceback (most recent call last):
  File "sample.py", line 7, in <module>
    """
Exception: ('foo', 'bar')

在这里,解释器"""在报告异常时也会报告。它似乎是在磁盘上的文件中查找这些信息,而不是通过加载到内存中的文件来运行程序。

我的困惑之源

以下是我跑步时发生的事情的心理模型python3 sample.py

  1. 解释器将 的内容加载sample.py到内存中
  2. 解释器进行词法分析、语义分析、代码生成等,产生机器码
  3. 生成的代码被发送到 CPU 并执行
  4. 如果出现错误,解释器会查询源代码的内存表示以产生错误消息

显然,我的心智模型存在缺陷。

我想知道的:

  1. 为什么 Python 解释器会查询磁盘上的文件以生成错误消息,而不是查看内存?
  2. 我对口译员所做工作的理解是否存在其他缺陷?
4

1 回答 1

1

根据@b_c链接的答案,

Python 不会跟踪任何已编译的字节码对应的源代码。在需要打印回溯之前,它甚至可能不会读取该源代码。

[...]

当 Python 需要打印回溯时,它会尝试查找与所涉及的所有堆栈帧相对应的源代码。您在堆栈跟踪中看到的文件名和行号都是 Python 必须继续进行的

[...]

默认sys.excepthook通过本地调用PyErr_Display,最终_Py_DisplaySourceLine用于显示单独的源代码行。_Py_DisplaySourceLine无条件地尝试在当前工作目录中查找文件(出于某种原因 - 被误导的优化?),然后调用_Py_FindSourceFile以搜索sys.path与该名称匹配的文件,如果工作目录没有它。

于 2019-10-10T14:48:24.093 回答