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

goh*_*goh 100 python

我理解起来很困难__file__.据我所知,__file__返回加载模块的绝对路径.

我遇到问题:我有abc.py一个声明print __file__,从/d/projects/ python abc.py返回运行abc.py.从/d/退货运行projects/abc.py.有什么原因吗?

agf*_*agf 94

文档:

__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`中加载当前目录__isn't__,则会获得绝对路径.如果在当前目录中加载模块,并在`sys.path`中加载当前目录__is__,则会获得相对路径. (4认同)

ana*_*nik 54

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

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

不确定它是否能解析符号链接.

传递相对路径的示例:

$ python script.py
Run Code Online (Sandbox Code Playgroud)

  • 对于Python 3.4.0("Python 3.4.0(默认,2014年4月11日,13:05:11)"[Linux下的GCC 4.8.2]而言,情况并非如此).在我的试验中,符号链接无法解决. (4认同)
  • @kevinarpe,/sf/ask/225452881/ (3认同)
  • 从 Python 3.9 开始,它现在始终是绝对路径 https://docs.python.org/3/whatsnew/3.9.html#other-language-changes (3认同)
  • `os.path.realpath(__ file __)`是解决符号链接的正确方法吗? (2认同)

Sim*_*AsG 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()
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

正如@techtonik所指出的,在Python 3.4+中,这将很好地工作,因为它__file__返回一个绝对路径.

  • ...除了“__main__”模块,其中“__file__”*可能*是相对路径。 (2认同)

Jav*_* TG 6

__file__可以是相对的或绝对的,具体取决于使用的 python 版本以及模块是否直接执行。

长话短说:

  • 从 python 3.5 到 3.8__file__如果直接调用模块,则设置为模块相对于当前工作目录的相对路径。否则它被设置为绝对路径。
  • 从 python 3.9 开始__file__即使直接执行相应的模块,也设置为绝对路径。

Python 3.9 的新增功能中解释了此行为(感谢@user0 的评论):

Python 现在获取在命令行上指定的脚本文件名的绝对路径(例如:)python3 script.py:模块__file__的属性__main__变成了绝对路径,而不是相对路径。现在,在 更改当前目录后,这些路径仍然有效os.chdir()。作为副作用,__main__在这种情况下,回溯还会显示模块帧的绝对路径。

玩具示例: 例如,具有以下设置(受此答案启发):

# x.py:
from pathlib import Path
import y
print(__file__)
print(Path(__file__))
print(Path(__file__).resolve())
Run Code Online (Sandbox Code Playgroud)
# y.py:
from pathlib import Path
print(__file__)
print(Path(__file__))
Run Code Online (Sandbox Code Playgroud)

x.pyy.py在同一目录中。进入该目录并执行后的不同输出:

python x.py
Run Code Online (Sandbox Code Playgroud)

是:

Python 3.5 - 3.8:

D:\py_tests\y.py
D:\py_tests\y.py
x.py
x.py
D:\py_tests\x.py
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • Python 的官方文档中有这样说的吗?我能找到的最接近的东西是[this](https://docs.python.org/3/whatsnew/3.9.html#other-language-changes)。 (2认同)

mar*_*rcz 5

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

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

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

作为例子,如果你有一个样品模块foo.py/tmp/的代码:

import sys
print(sys.path)
print (__file__)
Run Code Online (Sandbox Code Playgroud)

如果你进入 /tmp 你会得到:

>>> import foo
['', '/tmp', '/usr/lib/python3.3', ...]
./foo.py
Run Code Online (Sandbox Code Playgroud)

在 in 中/home/user,如果你添加/tmp你的,PYTHONPATH你会得到:

>>> import foo
['', '/tmp', '/usr/lib/python3.3', ...]
/tmp/foo.py
Run Code Online (Sandbox Code Playgroud)

即使添加了../../tmp,也会被归一化,结果是一样的。

但是,如果不是PYTHONPATH直接使用一些有趣的路径,您会得到与原因一样有趣的结果。

>>> import sys
>>> sys.path.append('../../tmp')
>>> import foo
['', '/usr/lib/python3.3', .... , '../../tmp']
../../tmp/foo.py
Run Code Online (Sandbox Code Playgroud)

Guido 在上面引用的线程中解释了为什么 python 不尝试转换绝对路径中的所有条目:

我们不想在每次导入时都调用 getpwd() .... getpwd() 相对较慢,有时会完全失败,

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