为什么在打印回溯时,Python会从当前目录进行读取?
问题描述
$ 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中的吗?
解决方案
不跟踪与任何已编译字节码对应的源代码。它甚至可能不会读取源代码,直到它需要打印回溯,例如,如果从.pyc
文件加载模块。
当Python需要打印回溯时,它会尝试查找与所有涉及的堆栈框架相对应的源代码。您在堆栈跟踪中看到的文件名和行号就是全部内容。如果它使用traceback
模块,代码路径将经过linecache
excludes filenames starting and ending with <
and >
中的一个部分,但默认的sys.excepthook
不经过该路径。
default sys.excepthook
通过本机调用PyErr_Display
,最终使用_Py_DisplaySourceLine
显示各个源代码行。_Py_DisplaySourceLine
无条件地尝试在当前工作目录中查找该文件(出于某种原因-误导优化?),然后调用_Py_FindSourceFile
搜索sys.path
匹配该名称的文件(如果工作目录中没有该文件)。通常,它不会找到<stdin>
或<string>
文件,当它找不到文件时,它会跳过打印源代码,但如果找到一个文件,它就会从该文件打印。
我最初认为可以通过使用-I
flag运行Python并将其置于隔离模式来防止出现这种情况。隔离模式的效果之一是从sys.path
中删除脚本的目录。实验证明,这并没有改变事情,也就是我意识到_Py_DisplaySourceLine
无论如何都会尝试工作目录。
<>
文件名来修复此问题非常简单,就像linecache
所做的那样。无条件在当前目录中搜索文件的代码也应更改。
相关文章