问题:模块__file__属性是绝对的还是相对的?
我在理解上有困难__file__
。据我了解,__file__
返回加载模块的绝对路径。
我在制作这个问题:我有abc.py
一个说法print __file__
,从运行/d/projects/
python abc.py
的回报abc.py
。从/d/
收益出发projects/abc.py
。有什么原因吗?
回答 0
从文档中:
__file__
是从中加载模块的文件的路径名(如果它是从文件加载的)。__file__
对于静态链接到解释器的C模块,该属性不存在。对于从共享库动态加载的扩展模块,它是共享库文件的路径名。
从@kindall链接的邮件列表线程中,对该问题进行评论:
我没有尝试对这个特定示例进行复制,但是原因是我们不想在每次导入时都调用getpwd(),也不想拥有某种进程内变量来缓存当前目录。(getpwd()相对较慢,有时可能会完全失败,并且尝试对其进行缓存有一定的错误风险。)
相反,我们要做的是site.py中的代码,该代码遍历sys.path的元素并将其转换为绝对路径。但是,此代码在将”插入sys.path的开头之前运行,因此sys.path的初始值为。
对于其余的内容,请考虑sys.path
不包括''
。
因此,如果您不在sys.path
包含模块的那一部分内,则将获得一条绝对路径。如果您位于sys.path
包含模块的那一部分内,则会得到一个相对路径。
如果您在当前目录中加载模块,而当前目录不在中sys.path
,则将获得绝对路径。
如果将模块加载到当前目录中,并且当前目录位于中sys.path
,则将获得相对路径。
回答 1
__file__
从Python 3.4开始是绝对的,除了直接使用相对路径执行脚本时除外:
__file__
现在,默认情况下,模块属性(和相关值)应始终包含绝对路径,唯一的exceptions是__main__.__file__
何时使用相对路径直接执行了脚本。(由Brett Cannon在bpo-18416中贡献。)
虽然不确定它是否解析符号链接。
传递相对路径的示例:
$ python script.py
回答 2
后面的简单示例:
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
借助@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
,如果添加,/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()相对较慢,有时可能会完全失败,
因此,您的路径将按原样使用。