我想知道在Python中确定当前脚本目录的最佳方法是什么。

我发现,由于调用Python代码的方法很多,很难找到一个好的解决方案。

以下是一些问题:

如果脚本使用exec, execfile执行,则__file__未定义 __module__只在模块中定义

用例:

。/ myfile.py python myfile.py / somedir / myfile.py python somedir / myfile.py Execfile ('myfile.py')(来自另一个脚本,可以位于另一个目录,并且可以有另一个当前目录。

我知道没有完美的解决方案,但我正在寻找解决大多数情况的最佳方法。

最常用的方法是os.path.dirname(os.path.abspath(__file__)),但如果你用exec()从另一个脚本执行脚本,这就行不通了。

警告

任何使用当前目录的解决方案都会失败,这可以根据脚本调用的方式有所不同,也可以在运行的脚本中更改。


当前回答

print(__import__("pathlib").Path(__file__).parent)

其他回答

如果您真的想了解通过execfile(…)调用脚本的情况,可以使用inspect模块推断文件名(包括路径)。据我所知,这将适用于你列出的所有情况:

filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))

注意:这个答案现在是一个包(也具有安全的相对导入功能)

https://github.com/heetbeet/locate

$ pip install locate

$ python
>>> from locate import this_dir
>>> print(this_dir())
C:/Users/simon

对于.py脚本和交互使用:

我经常使用脚本的目录(用于访问与它们一起存储的文件),但我也经常在交互式shell中运行这些脚本以进行调试。我将this_dir定义为:

运行或导入.py文件时,该文件的基目录。这总是正确的路径。 运行.ipyn笔记本时,当前工作目录。这始终是正确的路径,因为Jupyter将工作目录设置为.ipynb基本目录。 在REPL中运行时,当前工作目录。嗯,当代码从文件中分离出来时,实际的“正确路径”是什么?相反,在调用REPL之前,将更改到“正确路径”作为您的责任。

Python 3.4(及以上版本):

from pathlib import Path
this_dir = Path(globals().get("__file__", "./_")).absolute().parent

Python 2(及以上版本):

import os
this_dir = os.path.dirname(os.path.abspath(globals().get("__file__", "./_")))

解释:

Globals()将所有全局变量作为字典返回。 .get("__file__", "./_")如果globals()中存在键"__file__",则返回键"__file__"的值,否则返回提供的默认值"./_"。 其余的代码只是将__file__(或"./_")展开为一个绝对文件路径,然后返回该文件路径的基目录。

选择:

如果你确定__file__对你的周边代码可用,你可以简化为:

>= Python 3.4: this_dir = Path(__file__).absolute().parent >= Python 2: this_dir = os.path.dirname(os.path.abspath(__file__))

os.path.dirname(os.path.abspath(__file__))

确实是你能得到的最好的。

使用exec/execfile执行脚本是不寻常的;通常情况下,您应该使用模块基础结构来加载脚本。如果你必须使用这些方法,我建议在你传递给脚本的全局变量中设置__file__,这样脚本就可以读取该文件名。

没有其他方法可以在执行代码中获取文件名:正如您所注意到的,CWD可能在一个完全不同的地方。

import os
cwd = os.getcwd()

做你想做的事?我不确定你说的“当前脚本目录”到底是什么意思。您给出的用例的预期输出是什么?

在Python 3.4+中,你可以使用更简单的pathlib模块:

from inspect import currentframe, getframeinfo
from pathlib import Path

filename = getframeinfo(currentframe()).filename
parent = Path(filename).resolve().parent

你也可以使用__file__(当它可用时)来完全避免inspect模块:

from pathlib import Path
parent = Path(__file__).resolve().parent