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就这样使用