Skip to content

Python 脚本中获取脚本文件自身的路径

0 - TL;DR

答案:

python
project_base = Path(__file__).absolute().parents[1]
sys.path.append(str(project_base))

详细解释见下文。

1 - 问题来源

项目根目录为 project,其中的 scripts 目录内存放有一系列脚本 a.py, b.py, c.py 等,其中脚本的运行需要 import 项目中的某些模块。

text
project
 ├─scripts
 │  ├─a.py
 │  ├─b.py
 │  └─c.py
 ├─apps
 │  ├─module_1
 │  │  ├─...
 │  │  └─...
 │  ├─module_2
 ...

为此,在 import 之前,需要把项目的根目录加入到脚本运行时的 path 中(sys.path.append),需要确定脚本所在目录,由此推出上一级目录的路径。

2 - 错误写法

2.1 错误写法 1

python
project_base = Path(__file__).parents[1]
sys.path.append(str(project_base))

问题

__file__ 得到的是相对于当前工作路径的脚本文件的相对路径。

通过 python scripts/a.py 运行脚本时,__file__ == "scripts/a.py"

通过 python a.py 运行脚本时,__file__ == "a.py"。此时,Path(__file__).parents[1] 命令会因无法获取到父级目录而报错。

总结

__file__ 是相对路径,仅从相对路径获取到的父级深度不一定满足需要。

2.2 错误写法 2

python
project_base = Path(os.getcwd()).parents[0]
sys.path.append(str(project_base))

问题

启动 python 解释器时的所在的目录为当前工作目录,os.getcwd() 获取到的是这个路径。

现在在 scripts 下面运行脚本没有问题了,但是通过 Pycharm 调试时,Pycharm 会在项目根目录下启动脚本,因此 os.getcwd() 得到的是项目根目录的路径,此时获取的 project_base 就不对了。

总结

os.getcwd() 获取的是当前工作目录,随执行时的位置变化。

3 - 正确写法

正确写法是对写法 1 的改良:

python
project_base = Path(__file__).absolute().parents[1]
sys.path.append(str(project_base))

python 早期版本没有 pathlib 库,利用 os 库的等价写法如下:

python
project_base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_base)

4 - 总结

利用 Path().absolute()os.path.abspath 获取绝对路径,然后再获取父级目录。

Released under the MIT License.