为什么 Python 在打印回溯时从当前目录读取?
Why does Python read from the current directory when printing a traceback?
$ echo "Your code is bad and you should feel bad" > "<stdin>"
$ python
Python 3.6.0 (default, Dec 28 2016, 19:53:26)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + '2'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Your code is bad and you should feel bad
TypeError: unsupported operand type(s) for +: 'int' and 'str'
为什么 Python 会将字符串 "<stdin>"
与匹配该文件名的文件混淆?我不希望 Python 在遇到未处理的异常时尝试从我的磁盘中读取任何文件。
您也可以使用 "<string>"
文件名获取它:
$ echo "pining for the fjords" > "<string>"
$ python -c 'wat'
Traceback (most recent call last):
File "<string>", line 1, in <module>
pining for the fjords
NameError: name 'wat' is not defined
有什么方法可以防止这种行为,或者它是否被硬编码到 REPL 中?
Python 不会跟踪哪些源代码对应于任何已编译的字节码。在需要打印回溯之前,它甚至可能不会读取该源代码,例如,如果模块是从 .pyc
文件加载的。
当Python需要打印回溯时,就是它试图找到与所有涉及的堆栈帧对应的源代码的时候。你在堆栈跟踪中看到的文件名和行号都是 Python 必须继续的。如果它使用 traceback
模块,代码路径将通过 linecache
中 excludes filenames starting and ending with <
and >
的部分,但默认 sys.excepthook
不会通过该路径。
default sys.excepthook
goes through the native call PyErr_Display
, which eventually winds up using _Py_DisplaySourceLine
显示单独的源代码行。 _Py_DisplaySourceLine
无条件地尝试在当前工作目录中查找文件(出于某种原因 - 错误的优化?),然后调用 _Py_FindSourceFile
搜索 sys.path
匹配该名称的文件如果工作目录没有。通常,它不会找到 <stdin>
或 <string>
文件,当它找不到文件时它会跳过打印源代码,但如果找到一个,它会从该文件打印.
我最初认为您可以通过 运行 Python 和 -I
flag 将其置于隔离模式来防止这种情况。隔离模式的效果之一是从 sys.path
中删除脚本的目录。实验证明,这并没有改变什么,我意识到 _Py_DisplaySourceLine
无论如何都会尝试工作目录。
通过在本机代码路径中排除 <>
文件名来解决此问题非常简单,就像 linecache
所做的那样。无条件在当前目录搜索文件的代码也要改一下
$ echo "Your code is bad and you should feel bad" > "<stdin>"
$ python
Python 3.6.0 (default, Dec 28 2016, 19:53:26)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + '2'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Your code is bad and you should feel bad
TypeError: unsupported operand type(s) for +: 'int' and 'str'
为什么 Python 会将字符串 "<stdin>"
与匹配该文件名的文件混淆?我不希望 Python 在遇到未处理的异常时尝试从我的磁盘中读取任何文件。
您也可以使用 "<string>"
文件名获取它:
$ echo "pining for the fjords" > "<string>"
$ python -c 'wat'
Traceback (most recent call last):
File "<string>", line 1, in <module>
pining for the fjords
NameError: name 'wat' is not defined
有什么方法可以防止这种行为,或者它是否被硬编码到 REPL 中?
Python 不会跟踪哪些源代码对应于任何已编译的字节码。在需要打印回溯之前,它甚至可能不会读取该源代码,例如,如果模块是从 .pyc
文件加载的。
当Python需要打印回溯时,就是它试图找到与所有涉及的堆栈帧对应的源代码的时候。你在堆栈跟踪中看到的文件名和行号都是 Python 必须继续的。如果它使用 traceback
模块,代码路径将通过 linecache
中 excludes filenames starting and ending with <
and >
的部分,但默认 sys.excepthook
不会通过该路径。
default sys.excepthook
goes through the native call PyErr_Display
, which eventually winds up using _Py_DisplaySourceLine
显示单独的源代码行。 _Py_DisplaySourceLine
无条件地尝试在当前工作目录中查找文件(出于某种原因 - 错误的优化?),然后调用 _Py_FindSourceFile
搜索 sys.path
匹配该名称的文件如果工作目录没有。通常,它不会找到 <stdin>
或 <string>
文件,当它找不到文件时它会跳过打印源代码,但如果找到一个,它会从该文件打印.
我最初认为您可以通过 运行 Python 和 -I
flag 将其置于隔离模式来防止这种情况。隔离模式的效果之一是从 sys.path
中删除脚本的目录。实验证明,这并没有改变什么,我意识到 _Py_DisplaySourceLine
无论如何都会尝试工作目录。
通过在本机代码路径中排除 <>
文件名来解决此问题非常简单,就像 linecache
所做的那样。无条件在当前目录搜索文件的代码也要改一下