Python怎么获取脚本文件所在的绝对路径
详细讲解在Python中如何准确获取当前脚本文件所在的绝对路径,对比pathlib与os.path的用法,解析工作目录与脚本目录的本质区别,以及符号链接与特殊运行环境下的避坑要点。
pathlib:通过 Path(__file__).resolve() 获取脚本自身的绝对文件路径,调用 .parent 属性即可得到脚本所在的目录绝对路径;如果需要兼顾 Python 2 或习惯使用传统内置模块,则可以使用 os.path.dirname(os.path.abspath(__file__))。
图 1:Python 获取脚本自身所在绝对路径的两种标准方案速览
一、为什么不能直接用 os.getcwd()?
很多初学者在编写读取配置、加载同级资源文件的代码时,习惯性调用 os.getcwd() 或 Path.cwd()。这种写法在本地测试、且终端正好处于脚本所在文件夹运行时通常能够正常工作,但一旦项目被部署、作为系统定时任务(如 crontab)、或者在不同工作目录下被调用时,程序就会立刻报出 FileNotFoundError。
产生这一现象的根源在于:“当前工作目录”(Current Working Directory)与“脚本文件所在目录”(Script Directory)是完全不同的两个概念:
- 当前工作目录(CWD):是终端执行 Python 解释器时所在的目录。用户在哪个路径下输入
python ...,CWD 就是哪里。它是动态变化的。 - 脚本文件所在目录:是
.py脚本文件在磁盘中固定的存储位置,无论外部从哪个文件夹发起调用,它都是确定的。
图 2:当前工作目录(CWD)与脚本所在文件目录的差异与寻址影响
二、现代推荐方案:使用 pathlib 模块
从 Python 3.4 开始,标准库引入了面向对象的 pathlib 模块。在 Python 3 中编写新代码时,应优先使用 pathlib。它摆脱了繁杂的字符串拼接,语法清晰易读。
1. 获取脚本文件自身及所在目录的绝对路径
在你的脚本中,只需写下如下几行:
from pathlib import Path
# 获取当前脚本文件的绝对路径(指向 .py 文件本身)
script_path = Path(__file__).resolve()
# 获取当前脚本文件所在的目录的绝对路径(指向包含该脚本的文件夹)
script_dir = script_path.parent
print("脚本文件绝对路径:", script_path)
print("脚本所在目录路径:", script_dir)
脚本所在目录路径: /Users/alice/projects/demo
图 3:pathlib 链式调用各阶段的内部行为与返回值变化
2. 实用延伸:基于脚本目录安全拼接项目文件
获取脚本绝对目录后,最常见的需求是定位项目的配置文件、日志目录或数据包。pathlib 提供了重载的斜杠 / 运算符,让路径拼接非常自然,再也不用手动处理 Windows \ 与 Linux / 的差异:
from pathlib import Path
# 当前脚本所在目录
BASE_DIR = Path(__file__).resolve().parent
# 拼接同级或子目录资源文件
config_file = BASE_DIR / "config.json"
data_dir = BASE_DIR / "assets" / "images"
print("配置文件绝对路径:", config_file)
print("配置文件是否存在:", config_file.exists())
三、传统兼容方案:使用 os.path 模块
在旧项目维护、或者需要兼容老版本 Python 环境中,os.path 依然是最普遍的写法。它主要通过组合 os.path.abspath 和 os.path.dirname 实现。
import os
# 1. 获取脚本文件本身的绝对路径
script_file_path = os.path.abspath(__file__)
# 2. 获取脚本所在目录的绝对路径
script_dir_path = os.path.dirname(script_file_path)
# 也可以直接缩写为一行
script_dir = os.path.dirname(os.path.abspath(__file__))
print("脚本文件绝对路径:", script_file_path)
print("脚本所在目录路径:", script_dir)
虽然有时写 os.path.abspath(os.path.dirname(__file__)) 也能得到正确结果,但最佳顺序是先对 __file__ 执行 os.path.abspath。原因在于当通过 python test.py 直接运行当前目录脚本时,__file__ 的值是纯文件名 'test.py',此时如果先调 os.path.dirname('test.py') 会返回空字符串 '',虽然随后的 abspath('') 恰好会回退为当前工作目录,但逻辑不够直观严密。
四、关键细节与边界场景避坑
绝大多数常规脚本中使用上述方法已经足够稳健,但在以下三个特殊场景中,需要特别注意代码的执行边界。
图 4:符号链接解析差异与特殊运行环境下的处理要点
1. 符号链接(软链接)的处理:resolve 与 absolute 的区别
如果你的脚本是通过 Linux 软链接(ln -s)部署运行的,你需要明确自己想要的是“软链接所在的位置”还是“源文件真正所在的位置”:
Path(__file__).resolve()(对应os.path.realpath(__file__)):会追溯并解析软链接,返回真实源文件的绝对路径。绝大多数需要加载源码同级资源包的场景都应使用此方法。Path(__file__).absolute()(对应os.path.abspath(__file__)):不会解析符号链接,返回的是符号链接本身的路径。
2. 交互式解释器与 Jupyter Notebook
在 Python 交互式命令行(REPL)、python -c "..." 或是 Jupyter Notebook 单元格中执行代码时,是不存在 __file__ 这个全局变量的,直接访问会触发 NameError: name '__file__' is not defined。如果需要写出兼容两者的健壮代码,可以使用如下封装:
import sys
from pathlib import Path
def get_script_dir():
# 检查全局作用域中是否存在 __file__
if "__file__" in globals():
return Path(__file__).resolve().parent
# 交互式环境回退到当前工作目录
return Path.cwd()
current_dir = get_script_dir()
print("当前安全目录:", current_dir)
3. PyInstaller 打包后的路径获取
当你使用 PyInstaller 将 Python 脚本打包为单文件可执行程序时,程序运行时会将资源解压到操作系统的临时目录(sys._MEIPASS)。此时如果你希望获取可执行文件(.exe)所在的真实目录(比如读取 exe 同级下的外部配置文件),应该使用 sys.executable:
import sys
from pathlib import Path
def get_app_dir():
# 判断是否运行在 PyInstaller 冻结环境中
if getattr(sys, "frozen", False):
return Path(sys.executable).resolve().parent
return Path(__file__).resolve().parent
APP_DIR = get_app_dir()
print("应用基准目录:", APP_DIR)
五、方法选型与总结
获取脚本绝对路径的核心在于以 __file__ 为锚点,将其从启动时的相对表达解析为磁盘上的绝对物理位置。以下是常见 API 的对比速查:
| 实现方式 | 脚本所在目录写法 | 返回值类型 | 推荐指数 / 适用场景 |
|---|---|---|---|
| pathlib (首选) | Path(__file__).resolve().parent |
Path 对象 |
★★★★★ Python 3.4+ 现代代码推荐,语法优雅,跨平台友好 |
| os.path (经典) | os.path.dirname(os.path.abspath(__file__)) |
str 字符串 |
★★★★☆ 兼容 Python 2 或老旧工程 |
| 软链接源路径 | Path(__file__).resolve().parent |
Path 对象 |
★★★★★ 穿透软链接,准确定位真实代码位置 |
| 打包应用兼顾 | 根据 getattr(sys, 'frozen', False) 分支处理 |
Path 对象 |
★★★★★ 桌面软件发布、CLI 二进制分发场景 |
图 5:获取脚本绝对路径的完整技术路线与选择决策
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









