import os
A = os.path.join(os.path.dirname(__file__), '..')
B = os.path.dirname(os.path.realpath(__file__))
C = os.path.abspath(os.path.dirname(__file__))
我通常只是使用实际路径来硬编码这些内容。但这些确定运行时路径的语句有其原因,我真的很想了解os.path
模块,以便开始使用它。
import os
A = os.path.join(os.path.dirname(__file__), '..')
B = os.path.dirname(os.path.realpath(__file__))
C = os.path.abspath(os.path.dirname(__file__))
我通常只是使用实际路径来硬编码这些内容。但这些确定运行时路径的语句有其原因,我真的很想了解os.path
模块,以便开始使用它。
__file__
会被设置为其absolute路径。然后,您可以将其与其他函数一起使用,以找到文件所在的目录。A = os.path.join(os.path.dirname(__file__), '..')
# A is the parent directory of the directory where program resides.
B = os.path.dirname(os.path.realpath(__file__))
# B is the canonicalised (?) directory where the program resides.
C = os.path.abspath(os.path.dirname(__file__))
# C is the absolute path of the directory where the program resides.
import os
print(__file__)
print(os.path.join(os.path.dirname(__file__), '..'))
print(os.path.dirname(os.path.realpath(__file__)))
print(os.path.abspath(os.path.dirname(__file__)))
./text.py
,~/python/text.py
等等),看看这会有什么不同。首先,我想澄清一些混淆。__file__
不是通配符,而是一个属性。按照惯例,双下划线开头的属性和方法被认为是“特殊”的,并且具有特定的用途。
http://docs.python.org/reference/datamodel.html列出了许多特殊方法和属性,如果不是全部的话。
在这种情况下,__file__
是一个模块的属性(即一个模块对象)。在Python中,一个.py
文件就是一个模块。因此,import amodule
会有一个__file__
属性,在不同情况下具有不同的含义。
来自文档的摘录:
__file__
是加载模块时其源文件的路径名,如果它是从文件中加载的话。对于静态链接到解释器中的C模块,没有__file__
属性;对于从共享库动态加载的扩展模块,它是共享库文件的路径名。
在您的情况下,该模块在全局命名空间中访问自己的__file__
属性。
要查看此操作,请尝试以下内容:
# file: test.py
print globals()
print __file__
然后运行:
python test.py
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__file__':
'test_print__file__.py', '__doc__': None, '__package__': None}
test_print__file__.py
仅在这里添加一个快速说明(主要回答问题的标题而不是其描述),关于一项更改可能会使某些人感到困惑。从Python 3.4开始,__file__
的行为有了轻微的变化:
现在,默认情况下,模块
__file__
属性(和相关值)应始终包含绝对路径,唯一的例外是当脚本使用相对路径直接执行时的__main__.__file__
。(由Brett Cannon在问题18416中提出。)
示例:
直接调用模块x和间接调用模块y:
# 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__))
运行python3 x.py
会输出:
/home/aderchox/mytest/y.py
/home/aderchox/mytest/y.py
x.py
x.py
/home/aderchox/mytest/x.py
使用__file__
与各种os.path
模块结合使用,可以使所有路径相对于当前模块的目录位置。这样可以让您的模块/项目在其他计算机上具有可移植性。
在您的项目中,您可以执行以下操作:
A = '/Users/myname/Projects/mydevproject/somefile.txt'
如果您尝试使用像 /home/web/mydevproject/
这样的部署目录将其部署到服务器上,那么您的代码将无法正确找到路径。
作为对aderchox回答的补充,__file__
变量的行为在Python 3.9中再次进行了更改,现在在所有情况下它都是一个绝对路径。
运行相同的示例(但为了自我一致性,在此处复制):
# 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
$ python3.8 x.py
/private/tmp/y.py
/private/tmp/y.py
x.py
x.py
/private/tmp/x.py
$ python3.9 x.py
/private/tmp/y.py
/private/tmp/y.py
/private/tmp/x.py
/private/tmp/x.py
/private/tmp/x.py
source: https://docs.python.org/3/whatsnew/3.9.html#other-language-changes
召唤死灵
[仅在Python 3.7中测试过]
我使用:
os.sep.join(__file__.split(os.sep)[:-1]
而且我更喜欢它,相比于我看到的其他解决方案。这是一些我写的测试代码:
from timeit import Timer
from typing import List, Tuple
N = 100000
TIMEITOUT = [None]
def _p_timeit(stmt: str, setup: str = ""):
tte = Timer(f"TIMEITOUT[0]={stmt}", setup=f"{setup};from __main__ import TIMEITOUT").timeit(N)
print(f"{stmt:<54}|{tte:>17.10f} [output]: \"{TIMEITOUT[0]}\"")
return stmt, tte
def _p_header():
print(f"Testing w/ number={N} iterations\n{'=' * 72}")
print(f"{'Statement':<54}|{'Time':^17}\n{'-' * 72}")
def _p_compare(a: Tuple[str, float], b_l: List[Tuple[str, float]]):
print(f"\n{'=' * 72}\nComparing {a[0]} to all other statements:\n{'-' * 72}")
for b in b_l:
d = (b[1]-a[1])/a[1]
cmp = f"faster than" if d > 0 else f"slower than" if d < 0 else f"equally (t={a[1]}) as fast as"
print(f"{a[0]} was {(abs(d)*100):.2f}% {cmp} {b[0]}")
_p_header()
my_suggestion = _p_timeit("os.sep.join(__file__.split(os.sep)[:-1])", setup="import os")
others = [_p_timeit("os.path.abspath(os.path.dirname(__file__))", setup="import os"),
_p_timeit("Path(__file__).parent", setup="from pathlib import Path"),
_p_timeit("Path(__file__).resolve().parent", setup="from pathlib import Path")]
_p_compare(my_suggestion, others)
输出:
Testing w/ number=100000 iterations
========================================================================
Statement | Time
------------------------------------------------------------------------
os.sep.join(__file__.split(os.sep)[:-1]) | 0.0640765000 [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\lib"
os.path.abspath(os.path.dirname(__file__)) | 0.6156060000 [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\lib"
Path(__file__).parent | 0.7117664000 [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\lib"
Path(__file__).resolve().parent | 9.3563913000 [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\Lib"
========================================================================
Comparing os.sep.join(__file__.split(os.sep)[:-1]) to all other statements:
------------------------------------------------------------------------
os.sep.join(__file__.split(os.sep)[:-1]) was 860.74% faster than os.path.abspath(os.path.dirname(__file__))
os.sep.join(__file__.split(os.sep)[:-1]) was 1010.81% faster than Path(__file__).parent
os.sep.join(__file__.split(os.sep)[:-1]) was 14501.91% faster than Path(__file__).resolve().parent
ex1 = Path(__file__).parent/"myfilename.xyz"
ex2 = Path(__file__).parent/"whatever_folder/myfilename.xyz"
ex3 = Path(__file__).parent/"../whatever_folder/myfilename.xyz"
__file__
在某些情况下并没有定义,比如静态链接的 C 模块。我们不能指望__file__
总是可用。 - Chris Johnsonname '__file__' is not defined
。 - user1063287__file__
是模块加载时文件的路径名,如果是从文件加载的话。这意味着__file__
只能在脚本中运行时才有效,而不能在解释器中使用(除非你在解释器中导入了它...)。 - YOUNG__file__
会被设置为其路径。是哪个路径呢?抱歉我的英语不好。我可以说__file__
总是指向当前的脚本/模块/文件吗? - VimNing