模块__file__属性是绝对的还是相对的?

时间:2011-08-19 04:18:09

标签: python

我无法理解__file__。据我所知,__file__返回加载模块的绝对路径。

我遇到问题:我有abc.py一条语句print __file__,从/d/projects/ python abc.py开始运行abc.py。从/d/开始运行会返回projects/abc.py。有什么原因吗?

4 个答案:

答案 0 :(得分:90)

来自documentation

  

__file__是加载模块的文件的路径名(如果是从文件加载的)。对于静态链接到解释器的C模块,不存在__file__属性;对于从共享库动态加载的扩展模块,它是共享库文件的路径名。

从@kindall在评论中链接的mailing list thread问题:

  

我没有尝试重复这个特定的例子,但原因是   我们不希望每次导入都调用getpwd(),也不需要   想要某种进程内变量来缓存当前变量   目录。 (getpwd()相对较慢,有时可能会失败   直接,并试图缓存它有一定的错误风险。)

     

我们所做的是,site.py中的代码遍历了元素   sys.path并将它们转换为绝对路径。但是这段代码运行了   在''之前插入sys.path的前面,以便初始化   sys.path的值是''。

对于其余部分,请考虑sys.path不要包含''

因此,如果您不在包含该模块的sys.path部分,那么您将获得绝对路径。如果您位于包含该模块的sys.path部分内,您将获得相对路径

如果您在当前目录中加载模块,并且sys.path中的当前目录不是,您将获得绝对路径。

如果您在当前目录中加载模块,并且sys.path中的当前目录 ,您将获得相对路径。

答案 1 :(得分:48)

__file__是绝对since Python 3.4,除非直接使用相对路径执行脚本:

  

模块__file__属性(和相关值)现在应该始终包含绝对路径,当使用相对路径直接执行脚本时,__main__.__file__唯一例外。 (由Brett Cannon在bpo-18416提供。)

不确定它是否会解析符号链接。

传递相对路径的示例:

$ python script.py

答案 2 :(得分:14)

后期简单示例:

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__返回绝对路径。

答案 3 :(得分:4)

在@kindall提供的Guido邮件的帮助下,我们可以将标准导入过程理解为尝试在sys.path的每个成员中查找模块,并将文件作为此查找的结果(更多详细信息)在PyMOTW Modules and Imports。)。因此,如果模块位于sys.path中的绝对路径中,则结果是绝对的,但如果它位于sys.path中的相对路径中,则结果是相对的。

现在site.py启动文件只负责提供sys.path中的绝对路径,但初始''除外,所以如果不通过其他方式更改它,而不是设置PYTHONPATH (在sys.path前缀之前,它的路径也是绝对的),你将始终获得绝对路径,但是当通过当前目录访问模块时。

现在,如果你以一种有趣的方式欺骗​​sys.path,你就可以得到任何东西。

例如,如果foo.py中的示例模块/tmp/包含以下代码:

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()相对较慢,有时可能会彻底失败,

因此,您的路径