Python __file__属性是绝对的还是相对的?
我无法理解__file__
。 据我所知, __file__
返回模块加载的绝对path。
我有这样的问题:我有一个语句print __file__
abc.py
,从/d/projects/
python abc.py
返回abc.py
从/d/
返回projects/abc.py
。 任何原因为什么?
__file__
是从模块加载的文件的path名,如果它是从文件加载的。 对于静态链接到解释器的C模块,__file__
属性不存在; 对于从共享库dynamic加载的扩展模块,它是共享库文件的path名。
从@kindall链接的邮件列表中,
我没有尝试去重现这个特定的例子,但是原因是我们不想在每次导入时都调用getpwd(),也不想有某种进程内variables来caching当前目录。 (getpwd()相对较慢,有时可能会彻底失败,试图caching它有一定的错误风险。)
我们所做的是在site.py中的代码,它遍历sys.path的元素,并将它们转换为绝对path。 然而,这个代码在sys.path的前面插入''之前运行,所以sys.path的初始值是''。
对于其余部分,请考虑sys.path
不要包含''
。
所以,如果你不在包含模块的sys.path
部分,你会得到一个绝对path 。 如果你在包含这个模块的sys.path
部分,你会得到一个相对path 。
如果你在当前目录加载一个模块,并且当前目录不在 sys.path
,你会得到一个绝对path。
如果你在当前目录加载一个模块,并且当前目录在sys.path
,你会得到一个相对path。
从Python 3.4开始, __file__
总是绝对的。 不知道它是否parsing符号链接。
UPD :除了使用相对path直接执行的脚本之外。 喜欢这个:
$ python script.py
后期简单的例子:
from os import path, getcwd, chdir def print_my_path(): print('cwd: {}'.format(getcwd())) print('__file__:{}'.format(__file__)) print('abspath: {}'.format(path.abspath(__file__))) print_my_path() chdir('..') print_my_path()
在Python-2。*下,第二个调用错误地根据当前目录确定path.abspath(__file__)
:
cwd: C:\codes\py __file__:cwd_mayhem.py abspath: C:\codes\py\cwd_mayhem.py cwd: C:\codes __file__:cwd_mayhem.py abspath: C:\codes\cwd_mayhem.py
正如@techtonik在Python 3.4+中指出的那样,这将会正常工作,因为__file__
返回一个绝对path。
在@kindall提供的Guido邮件的帮助下,我们可以将标准导入过程理解为试图在sys.path
每个成员中find模块,并将文件作为此查找的结果( PyMOTW模块和导入中的更多详细信息)。 所以如果模块位于sys.path
中的绝对path中,结果是绝对的,但是如果它位于sys.path
中的相对path中,则结果是相对的。
现在, site.py
启动文件负责在sys.path
中传递唯一的绝对path,除了最初的''
,所以如果你不通过设置PYTHONPATH(其path也是绝对的,在加前缀sys.path
),你会得到一个绝对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
而是直接使用一些有趣的path,那么结果就像原因一样有趣。
>>> import sys >>> sys.path.append('../../tmp') >>> import foo ['', '/usr/lib/python3.3', .... , '../../tmp'] ../../tmp/foo.py
Guido在上面引用的线程中解释了为什么python不会尝试转换绝对path中的所有条目:
我们不想在每次导入时都调用getpwd()。getpwd()相对较慢,有时可能会彻底失败,
所以你的path就这样使用了 。