模块的 __file__ 属性是绝对路径还是相对路径?
我对 __file__
有点困惑。根据我的理解,__file__
会返回加载这个模块时的绝对路径。
我遇到的问题是这样的:我有一个 abc.py
文件,里面有一句话 print __file__
。当我在 /d/projects/
目录下运行 python abc.py
时,它返回的是 abc.py
。但是当我在 /d/
目录下运行时,它返回的是 projects/abc.py
。这是为什么呢?
5 个回答
这里有一个简单的例子:
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__
会返回一个绝对路径。
__file__
从 Python 3.4 开始默认是绝对路径,除了当你直接用相对路径执行一个脚本的时候:
模块的
__file__
属性(以及相关的值)现在默认应该总是包含绝对路径,唯一的例外是当一个脚本直接用相对路径执行时,__main__.__file__
会是相对路径。(这个改动是由 Brett Cannon 提出的,详细信息可以查看 bpo-18416。)
不过我不确定它是否会解析符号链接。
下面是一个使用相对路径的例子:
$ python script.py
__file__
在 Python 3.9 及以上版本中保证是一个绝对路径。
在 Python 3.4 的更新说明中提到,(更新日志)
模块的
__file__
属性(以及相关值)现在默认应该总是包含绝对路径,唯一的例外是当脚本直接使用相对路径执行时的__main__.__file__
。
在 Python 3.9 的更新说明中提到,(更新日志):
...
__main__
模块的__file__
属性变成了绝对路径。
根据 文档:
如果模块是从文件加载的,那么
__file__
属性就是加载该模块的文件的路径。对于某些类型的模块,比如静态链接到解释器的 C 模块,__file__
属性可能不存在。对于从共享库动态加载的扩展模块,它是共享库文件的路径。
在 @kindall 的评论中提到的 邮件列表讨论中提到:
我没有尝试重现这个特定的例子,但原因是我们不想在每次导入时都调用 getpwd(),也不想有某种进程内变量来缓存当前目录。(getpwd() 相对较慢,有时可能会失败,而尝试缓存它也有一定的错误风险。)
我们所做的是在 site.py 中编写代码,遍历 sys.path 中的元素并将它们转换为绝对路径。不过这段代码在 '' 被插入到 sys.path 的最前面之前就运行了,所以 sys.path 的初始值是 ''。
接下来,考虑 sys.path
不包含 ''
。
所以,如果你在不包含模块的 sys.path
部分外部,你会得到一个绝对路径。 如果你在包含模块的 sys.path
部分内部,你会得到一个相对路径。
如果你在当前目录加载一个模块,而当前目录不在 sys.path
中,你会得到一个绝对路径。
如果你在当前目录加载一个模块,而当前目录在 sys.path
中,你会得到一个相对路径。