如何让Python脚本摆脱绝对路径依赖,在任意工作目录下正常加载相对路径文件
解决方案:通过调用栈自动定位调用脚本的目录
这个问题我之前也碰到过,核心就是要让Config模块自动拿到加载它的脚本(也就是script.py)的实际目录,而不是模块自身的路径。你之前用__file__拿到的是module.py的路径,肯定找不到config.json,换个思路——用Python的inspect模块追踪调用栈就能解决。
1. 修改my_utilities/module.py中的Config类
在Config的初始化方法里,通过调用栈定位到调用它的脚本路径,再自动拼接相对路径的配置文件:
# my_utilities/module.py import inspect from pathlib import Path import json class Config: def __init__(self, relative_path): # 获取调用栈:索引0是当前__init__方法,索引1是调用它的代码所在栈帧 caller_frame = inspect.stack()[1] # 提取调用者的脚本文件绝对路径 caller_script_path = Path(caller_frame.filename) # 拿到脚本所在的目录 caller_script_dir = caller_script_path.parent # 拼接成配置文件的绝对路径 self.full_config_path = caller_script_dir / relative_path # 后续加载配置的逻辑(示例) with open(self.full_config_path, 'r') as f: self.data = json.load(f)
2. 在script.py中保持相对路径写法
完全不需要修改现有代码,依然用相对路径传入即可:
# script.py from my_utilities.module import Config config_path = 'config.json' conf = Config(config_path) # 可选:打印路径验证是否正确 print(conf.full_config_path)
原理说明
inspect.stack()会返回当前的调用栈帧列表,每个栈帧包含调用者的文件路径、行号等信息。- 取索引
[1]的栈帧,对应的就是直接调用Config()的代码(也就是script.py里的那行代码),从这里拿到的filename就是script.py的绝对路径。 - 用
Path类的parent属性获取脚本所在目录,再和传入的相对配置路径拼接,就能得到配置文件的绝对路径——不管当前工作目录是脚本本身的目录,还是crontab默认的/usr/bin,都能精准找到文件。
额外优化建议
- 兼容手动指定路径:可以给
Config加个可选参数,允许手动传入目录,兼顾特殊场景:def __init__(self, relative_path, target_dir=None): if target_dir: self.full_config_path = Path(target_dir) / relative_path else: # 自动获取调用者目录的逻辑 caller_frame = inspect.stack()[1] caller_script_path = Path(caller_frame.filename) caller_script_dir = caller_script_path.parent self.full_config_path = caller_script_dir / relative_path - 性能提示:
inspect.stack()会遍历调用栈,对高频调用场景可能有轻微性能影响,但对于脚本或定时任务这种场景完全可以忽略。
测试验证
不管你在任意目录执行脚本,还是通过crontab调度:
# 在非脚本目录执行 python3 /path/to/actual_script_dir/script.py # crontab中的调度命令 0 3 * * * /usr/bin/python3 /path/to/actual_script_dir/script.py
脚本都能正确加载config.json文件。
内容的提问来源于stack exchange,提问作者Gnudiff
相关产品推荐
相关产品推荐

