我对__file__
的理解有些困难。据我所知,__file__
返回模块被加载时的绝对路径。
我遇到了如下问题:我有一个abc.py
文件,其中只包含一条语句print __file__
,当在/d/projects/
目录下运行python abc.py
时,会返回abc.py
;而在/d/
目录下运行则返回projects/abc.py
。这是什么原因呢?
我对__file__
的理解有些困难。据我所知,__file__
返回模块被加载时的绝对路径。
我遇到了如下问题:我有一个abc.py
文件,其中只包含一条语句print __file__
,当在/d/projects/
目录下运行python abc.py
时,会返回abc.py
;而在/d/
目录下运行则返回projects/abc.py
。这是什么原因呢?
__file__
在 Python 3.9+ 中保证是绝对路径。
在 Python 3.4 中 (changelog)。
现在,模块的
__file__
属性(以及相关值)默认情况下应该始终包含绝对路径,唯一的例外是当脚本使用相对路径直接执行时的__main__.__file__
。
在 Python 3.9 中 (changelog):
...
__main__
模块的__file__
属性变为绝对路径
sys.path
中,将会得到一个绝对路径。如果你在当前目录下加载一个模块,且当前目录__在__sys.path
中,将会得到一个相对路径。 - agfsys.path
不包括 ''
。 - agf__file__
是绝对路径自 Python 3.4 开始, 但在使用相对路径直接执行脚本时除外:
默认情况下,模块
__file__
属性(及相关值)现在应始终包含绝对路径,唯一的例外是当使用相对路径直接执行脚本时,__main__.__file__
。 (由 Brett Cannon 在 bpo-18416 中贡献。)
不确定它是否解析符号链接。
传递相对路径的示例:
$ python script.py
Python 3.4.0(默认版本,Apr 11 2014,13:05:11)[GCC 4.8.2] on linux
),这不是真实情况。在我的测试中,符号链接未被解析。 - Frozen Flame简单的延迟示例:
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__
可能是相对路径。 - 0xC0000022Lsys.path
的每个成员中找到模块,并将文件作为此查找的结果(有关详细信息,请参阅PyMOTW Modules and Imports)。因此,如果模块位于sys.path
的绝对路径中,则结果是绝对的,但如果它位于sys.path
的相对路径中,则结果是相对的。
现在,site.py
启动文件负责仅传递sys.path
中的绝对路径,除了初始值''
之外,因此,如果您不通过设置PYTHONPATH(其路径也会在加上sys.path
之前变为绝对路径)而改变它,您将始终获得绝对路径,但当通过当前目录访问模块时。
现在,如果您以一种有趣的方式欺骗sys.path
,则可以获得任何内容。
例如,如果您在/tmp/
中有一个名为foo.py
的样本模块,其中包含以下代码:
import sys
print(sys.path)
print (__file__)
>>> 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()相对较慢,有时可能完全失败。
因此,您的路径将 按原样使用。
__file__
可以是相对路径或绝对路径,这取决于使用的 Python 版本以及模块是否直接执行。
简而言之:
__file__
设置为相对于当前工作目录的模块路径。否则,它将被设置为绝对路径。__file__
也会被设置为绝对路径。例如,有以下设置(受此 answer 的启发):
# x.py:
from pathlib import Path
import y
print(__file__)
print(Path(__file__))
print(Path(__file__).resolve())
# y.py:
from pathlib import Path
print(__file__)
print(Path(__file__))
x.py
和 y.py
。进入该目录并执行后,会得到不同的输出结果。python x.py
是:
Python 3.5 - 3.8:
D:\py_tests\y.py
D:\py_tests\y.py
x.py
x.py
D:\py_tests\x.py
Python 3.9 - 3.11
D:\py_tests\y.py
D:\py_tests\y.py
D:\py_tests\x.py
D:\py_tests\x.py
D:\py_tests\x.py
__file__
始终是一个绝对路径,永远不会是相对路径了吗? - undefined__file__
总是一个绝对路径。 - undefinedos.chdir()
改变了工作目录(即调用__main__
模块的目录,如上面的例子中的D:\py_tests
),__main__
模块的__file__
属性将会无效。这是因为__file__
存储了一个常量相对路径,不受os.chdir()
产生的变化影响。在Python 3.9之后,由于__file__
包含了一个绝对路径,它的值在os.chdir()
产生的变化之后仍然有效。 - undefined