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


107

我在理解上有困难__file__。据我了解,__file__返回加载模块的绝对路径。

我在制作这个问题:我有abc.py一个说法print __file__,从运行/d/projects/ python abc.py的回报abc.py。从/d/收益出发projects/abc.py。有什么原因吗?



Answers:


98

文档中

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

从@kindall链接的邮件列表线程中,对该问题进行评论:

我没有尝试对这个特定示例进行复制,但是原因是我们不想在每次导入时都调用getpwd(),也不想拥有某种进程内变量来缓存当前目录。(getpwd()相对较慢,有时可能会完全失败,并且尝试对其进行缓存有一定的错误风险。)

相反,我们要做的是site.py中的代码,该代码遍历sys.path的元素并将其转换为绝对路径。但是,此代码在将''插入sys.path的开头之前运行,因此sys.path的初始值为。

对于其余的内容,请考虑sys.path不包括''

因此,如果您不在sys.path包含模块的那一部分内,则将获得一条绝对路径。如果您位于sys.path包含模块的那一部分内,则会得到一个相对路径

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

如果将模块加载到当前目录中,并且当前目录位于sys.path,则将获得相对路径。


这样做是否意味着如果从''到模块之间存在路径,则将使用相对路径,如果不使用绝对路径,则将使用相对路径,因为sys.path的其余部分都是绝对路径
。.– goh

4
如果您在当前目录中加载模块,而当前目录不在sys.path,则将获得绝对路径。如果将模块加载到当前目录中,并且当前目录位于sys.path,则将获得相对路径。
2011年

请记住,为此目的,sys.path不包括''
2011年

知道了,但是@agf,如果我从/ home使用python /foo/abc.py,我想sys.path中包含模块的部分是/ home / foo,而我的当前目录是/ home /,为什么打印文件给我一个相对路径?
Goh

55

__file__从Python 3.4开始是绝对的,除了直接使用相对路径执行脚本时除外:

__file__现在,默认情况下,模块属性(和相关值)应始终包含绝对路径,唯一的例外是__main__.__file__何时使用相对路径直接执行了脚本。(由Brett Cannon在bpo-18416中贡献。)

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

传递相对路径的示例:

$ python script.py

1
谢谢。这是很难追踪的事实!
meawoppl 2014年

4
对于Python 3.4.0(Python 3.4.0 (default, Apr 11 2014, 13:05:11) [GCC 4.8.2] on linux)并非如此。在我的试验中,符号链接没有解决。
冰雪奇缘》 2015年

@FrozenFlame,如果3.4.1 无法解决问题,请随时向bugs.python.org报告。
anatoly techtonik,2015年

2
os.path.realpath(__file__)解决符号链接的正确方法?
kevinarpe


16

后面的简单示例:

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__返回绝对路径,因此可以很好地工作。


...除了__main__模块,其中__file__ 可能是相对路径。
0xC0000022L19年

5

借助@kindall提供的Guido邮件的帮助,我们可以理解标准的导入过程,即试图在其中的每个成员中查找模块sys.path,并以此查找的结果进行归档(更多详细信息,请参见PyMOTW Modules and Imports。)。因此,如果模块位于绝对路径中,sys.path则结果为绝对,但如果模块位于相对路径中,sys.path则结果为相对。

现在,site.py启动文件将只在in中提供绝对路径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,如果添加,/tmpPYTHONPATH将得到:

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

因此,您的路径将按原样使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.