借助@kindall 提供的Guido 邮件,我们可以将标准导入过程理解为尝试在sys.path 的每个成员中查找模块,并将此查找的结果文件(更多细节在@ 987654321@.)。因此,如果模块位于sys.path 中的绝对路径中,则结果是绝对的,但如果它位于sys.path 中的相对路径中,则结果是相对的。
现在site.py 启动文件只负责传递sys.path 中的绝对路径,除了初始的'',所以如果你不通过设置 PYTHONPATH 以外的其他方式更改它(其路径也已创建绝对的,在前缀sys.path)之前,你总是会得到一个绝对路径,但是当通过当前目录访问模块时。
现在,如果你以一种有趣的方式欺骗 sys.path,你可以得到任何东西。
例如,如果您在 /tmp/ 中有一个示例模块 foo.py,代码如下:
import sys
print(sys.path)
print (__file__)
如果你进入 /tmp 你会得到:
>>> import foo
['', '/tmp', '/usr/lib/python3.3', ...]
./foo.py
当在/home/user 中时,如果你添加/tmp 你的PYTHONPATH 你会得到:
>>> import foo
['', '/tmp', '/usr/lib/python3.3', ...]
/tmp/foo.py
即使加上../../tmp,也会被归一化,结果是一样的。
但是如果你不使用PYTHONPATH,而是直接使用一些有趣的路径
你得到的结果和原因一样有趣。
>>> import sys
>>> sys.path.append('../../tmp')
>>> import foo
['', '/usr/lib/python3.3', .... , '../../tmp']
../../tmp/foo.py
Guido 在上面引用的线程中解释了为什么 python 不尝试转换绝对路径中的所有条目:
我们不想在每次导入时都调用 getpwd() ....
getpwd() 相对较慢,有时会彻底失败,
所以你的路径被原样使用。